<!doctype html>
<html lang="zh-CN">
<head>

    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    
    <meta name="referrer" content="no-referrer-when-downgrade">
    

    <title>35分钟教你学会go | 早起的年轻人</title>
    <meta property="og:title" content="35分钟教你学会go - 早起的年轻人">
    <meta property="og:type" content="article">
        
    <meta property="article:published_time" content='2021-09-09T13:33:10&#43;08:00'>
        
        
    <meta property="article:modified_time" content='2021-09-09T13:33:10&#43;08:00'>
        
    <meta name="Keywords" content="Flutter，golang,go语言,go语言笔记,飞雪无情,java,android,博客,项目管理,python,软件架构,公众号,小程序">
    <meta name="description" content="35分钟教你学会go">
        
    <meta name="author" content="luckly">
    <meta property="og:url" content="https://luckly.work/post/go_basic/35%E5%88%86%E9%92%9F%E6%95%99%E4%BD%A0%E5%AD%A6%E4%BC%9Ago/">
    <link rel="shortcut icon" href='/favicon.ico'  type="image/x-icon">

    <link rel="stylesheet" href='/css/normalize.css'>
    <link rel="stylesheet" href='/css/style.css'>
    <script type="text/javascript" src="//cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>

    
    
    
        <link href="https://cdn.bootcdn.net/ajax/libs/fancybox/3.5.7/jquery.fancybox.min.css" rel="stylesheet">
    
    
    
    
        <link rel="stylesheet" href='/css/douban.css'>
    
        <link rel="stylesheet" href='/css/other.css'>
    
</head>

<link rel="stylesheet"
      href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.2.0/styles/default.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.2.0/highlight.min.js"></script>
<body>
    <header id="header" class="clearfix">
    <div class="container">
        <div class="col-group">
            <div class="site-name ">
                
                    <a id="logo" href="https://luckly.work/">
                        早起的年轻人
                    </a>
                
                <p class="description">专注于Flutter、Android、Java、Go语言(golang)、移动互联网、项目管理、软件架构</p>
            </div>
            <div>
                <nav id="nav-menu" class="clearfix">
                    <a class="current" href="https://luckly.work/">首页</a>
                    
                    <a  href="https://luckly.work/categories/" title="分类">分类</a>
                    
                    <a  href="https://luckly.work/tags/" title="标签">标签</a>
                    
                    <a  href="https://luckly.work/archives/" title="归档">归档</a>
                    
                    <a  href="https://luckly.work/about/" title="关于我">关于我</a>
                    
                    <a  href="https://github.com/ITmxs/" title="github">github</a>
                    
                </nav>
            </div>
        </div>
    </div>
</header>

    <div id="body">
        <div class="container">
            <div class="col-group">

                <div class="col-8" id="main">
                    
<div class="res-cons">
    <style type="text/css">
    .post-toc {
        position: fixed;
        width: 200px;
        margin-left: -210px;
        padding: 5px 10px;
        font-family: Athelas, STHeiti, Microsoft Yahei, serif;
        font-size: 12px;
        border: 1px solid rgba(0, 0, 0, .07);
        border-radius: 5px;
        background-color: rgba(255, 255, 255, 0.98);
        background-clip: padding-box;
        -webkit-box-shadow: 1px 1px 2px rgba(0, 0, 0, .125);
        box-shadow: 1px 1px 2px rgba(0, 0, 0, .125);
        word-wrap: break-word;
        white-space: nowrap;
        -webkit-box-sizing: border-box;
        box-sizing: border-box;
        z-index: 999;
        cursor: pointer;
        max-height: 70%;
        overflow-y: auto;
        overflow-x: hidden;
    }

    .post-toc .post-toc-title {
        width: 100%;
        margin: 0 auto;
        font-size: 20px;
        font-weight: 400;
        text-transform: uppercase;
        text-align: center;
    }

    .post-toc .post-toc-content {
        font-size: 15px;
    }

    .post-toc .post-toc-content>nav>ul {
        margin: 10px 0;
    }

    .post-toc .post-toc-content ul {
        padding-left: 20px;
        list-style: square;
        margin: 0.5em;
        line-height: 1.8em;
    }

    .post-toc .post-toc-content ul ul {
        padding-left: 15px;
        display: none;
    }

    @media print,
    screen and (max-width:1057px) {
        .post-toc {
            display: none;
        }
    }
</style>
<div class="post-toc" style="position: absolute; top: 188px;">
    <h2 class="post-toc-title">文章目录</h2>
    <div class="post-toc-content">
        <nav id="TableOfContents">
  <ul>
    <li><a href="#命名返回值">命名返回值</a></li>
    <li><a href="#变量的初始化">变量的初始化</a></li>
    <li><a href="#短变量声明">短变量声明</a></li>
    <li><a href="#基本类型">基本类型</a></li>
    <li><a href="#零值">零值</a></li>
    <li><a href="#类型转换">类型转换</a></li>
    <li><a href="#类型推导">类型推导</a></li>
    <li><a href="#常量">常量</a></li>
    <li><a href="#数值常量">数值常量</a></li>
    <li><a href="#for">for</a></li>
    <li><a href="#for续">for(续)</a></li>
    <li><a href="#for-是-go-中的-while">for 是 Go 中的 “while”</a></li>
    <li><a href="#无限循环">无限循环</a></li>
    <li><a href="#if">if</a></li>
    <li><a href="#if-的简短语句">if 的简短语句</a></li>
    <li><a href="#if-和-else">if 和 else</a></li>
    <li><a href="#练习循环与函数">练习：循环与函数</a></li>
    <li><a href="#switch">switch</a></li>
    <li><a href="#switch-的求值顺序">switch 的求值顺序</a></li>
    <li><a href="#没有条件的-switch">没有条件的 switch</a></li>
    <li><a href="#defer">defer</a></li>
    <li><a href="#defer-栈">defer 栈</a></li>
    <li><a href="#指针">指针</a></li>
    <li><a href="#结构体">结构体</a></li>
    <li><a href="#结构体字段">结构体字段</a></li>
    <li><a href="#结构体指针">结构体指针</a></li>
    <li><a href="#结构体文法">结构体文法</a></li>
    <li><a href="#数组">数组</a></li>
    <li><a href="#切片">切片</a></li>
    <li><a href="#切片就像数组的引用">切片就像数组的引用</a></li>
    <li><a href="#切片文法">切片文法</a></li>
    <li><a href="#切片的默认行为">切片的默认行为</a></li>
    <li><a href="#切片的长度与容量">切片的长度与容量</a></li>
    <li><a href="#nil-切片">nil 切片</a></li>
    <li><a href="#用-make-创建切片">用 make 创建切片</a></li>
    <li><a href="#切片的切片">切片的切片</a></li>
    <li><a href="#向切片追加元素">向切片追加元素</a></li>
    <li><a href="#range">Range</a></li>
    <li><a href="#range续">range(续)</a></li>
    <li><a href="#练习切片">练习：切片</a></li>
    <li><a href="#映射">映射</a></li>
    <li><a href="#映射的文法">映射的文法</a></li>
    <li><a href="#映射的文法续">映射的文法(续)</a></li>
    <li><a href="#修改映射">修改映射</a></li>
    <li><a href="#练习映射">练习：映射</a></li>
    <li><a href="#函数值">函数值</a></li>
    <li><a href="#函数的闭包">函数的闭包</a></li>
    <li><a href="#练习斐波纳契闭包">练习：斐波纳契闭包</a></li>
    <li><a href="#方法">方法</a></li>
    <li><a href="#方法即函数">方法即函数</a></li>
    <li><a href="#方法续">方法(续)</a></li>
    <li><a href="#指针接收者">指针接收者</a></li>
    <li><a href="#指针与函数">指针与函数</a></li>
    <li><a href="#方法与指针重定向">方法与指针重定向</a></li>
    <li><a href="#方法与指针重定向续">方法与指针重定向(续)</a></li>
    <li><a href="#选择值或指针作为接收者">选择值或指针作为接收者</a></li>
    <li><a href="#接口">接口</a></li>
    <li><a href="#映射的文法-1">映射的文法</a></li>
    <li><a href="#接口与隐式实现">接口与隐式实现</a></li>
    <li><a href="#接口值">接口值</a></li>
    <li><a href="#底层值为-nil-的接口值">底层值为 nil 的接口值</a></li>
    <li><a href="#nil-接口值">nil 接口值</a></li>
    <li><a href="#空接口">空接口</a></li>
    <li><a href="#类型断言">类型断言</a></li>
    <li><a href="#类型选择">类型选择</a></li>
    <li><a href="#stringer">Stringer</a></li>
    <li><a href="#练习stringer">练习：Stringer</a></li>
    <li><a href="#错误">错误</a></li>
    <li><a href="#练习错误">练习：错误</a></li>
    <li><a href="#reader">Reader</a></li>
    <li><a href="#练习reader">练习：Reader</a></li>
    <li><a href="#练习rot13reader">练习：rot13Reader</a></li>
    <li><a href="#图像">图像</a></li>
    <li><a href="#练习图像">练习：图像</a></li>
    <li><a href="#go-程">Go 程</a></li>
    <li><a href="#信道">信道</a></li>
    <li><a href="#带缓冲的信道">带缓冲的信道</a></li>
    <li><a href="#range-和-close">range 和 close</a></li>
    <li><a href="#select-语句">select 语句</a></li>
    <li><a href="#默认选择">默认选择</a></li>
    <li><a href="#练习等价二叉查找树">练习：等价二叉查找树</a></li>
    <li><a href="#练习等价二叉查找树-1">练习：等价二叉查找树</a></li>
    <li><a href="#syncmutex">sync.Mutex</a></li>
    <li><a href="#练习web-爬虫">练习：Web 爬虫</a></li>
    <li><a href="#接下来去哪">接下来去哪？</a></li>
  </ul>
</nav>
    </div>
</div>
<script type="text/javascript">
    $(document).ready(function () {
        var postToc = $(".post-toc");
        if (postToc.length) {
            var leftPos = $("#main").offset().left;
            if(leftPos<220){
                postToc.css({"width":leftPos-10,"margin-left":(0-leftPos)})
            }

            var t = postToc.offset().top - 20,
                a = {
                    start: {
                        position: "absolute",
                        top: t
                    },
                    process: {
                        position: "fixed",
                        top: 20
                    },
                };
            $(window).scroll(function () {
                var e = $(window).scrollTop();
                e < t ? postToc.css(a.start) : postToc.css(a.process)
            })
        }
    })
</script>
    <article class="post">
        <header>
            <h1 class="post-title">35分钟教你学会go</h1>
        </header>
        <date class="post-meta meta-date">
            2021年9月9日
        </date>
        
        <div class="post-meta">
            <span>|</span>
            
            <span class="meta-category"><a href='/categories/go'>go</a></span>
            
        </div>
        
        
        <div class="post-meta">
            <span id="busuanzi_container_page_pv">|<span id="busuanzi_value_page_pv"></span><span>
                    阅读</span></span>
        </div>
        
        
        <div class="post-content">
            <p>Go 或 Golang 是一种开源编程语言，由三位 Google 员工设计：<a href="https://translate.google.com/translate?sl=auto&amp;tl=en&amp;u=https%3A%2F%2Fde.wikipedia.org%2Fwiki%2FRobert_Griesemer">Robert Griesemer</a>、<a href="https://en.wikipedia.org/wiki/Rob_Pike">Rob Pike</a>和<a href="https://en.wikipedia.org/wiki/Ken_Thompson">Ken Thompson</a>。在 Go 开发之初，Google 的开发人员必须维护数百万行不断更新的代码。将他们的代码转换成工作程序需要花费大量时间，从几分钟到几小时不等！由于每个开发人员都需要经历相同的过程，这个问题甚至更加复杂。为了解决这些问题，Go 的设计者旨在<a href="https://talks.golang.org/2012/splash.article">“消除 Google 软件开发的缓慢和笨拙，从而使流程更加高效和可扩展”</a>。</p>
<p>换句话说，Go 的目的是让开发人员更快更容易地开发。它具有垃圾收集等现代功能，还利用内置并发支持的强大多核计算机功能。Go 的特性和速度的吸引力引起了许多不同类型的开发人员的兴趣，包括：应用程序开发人员和基础设施团队。随着 Go 的采用率不断提高，我们很可能会看到它在应用程序、Web 开发、<a href="https://en.wikipedia.org/wiki/Command-line_interface">命令行界面</a>和许多其他实现中的使用范围进一步扩大！</p>
<p>之前，我们可以充分利用围棋，我们首先必须<em>走</em>的如何读取和运行Go程序的基础上。完成整个课程后，请阅读我们<a href="https://www.codecademy.com/articles/setting-up-go-locally">在本地开发围棋</a>的<a href="https://www.codecademy.com/articles/setting-up-go-locally">指南，</a>以设置您的计算机并在您自己的计算机上创建围棋程序！</p>
<p>编译</p>
<p>当我们编写 Go 代码时，我们正在编写它以供我们自己和其他开发人员阅读。我们能够理解代码及其意图。另一方面，计算机不理解 Go 代码，因此无法直接了解我们的代码意味着/做什么。计算机能理解的是一系列 0 和 1(或二进制)。为了将 Go 代码转换为二进制，Go 有一个 <em>编译器</em>，这是一种将 Go 代码转换为计算机可以理解的程序的软件。翻译后的代码称为<em>可执行文件</em>或<em>二进制</em>文件。然后我们可以运行可执行文件，该可执行文件将执行我们编写的 Go 程序要做的事情。</p>
<p>为了告诉编译器编译 Go 程序，我们首先导航到我们的终端(在 Mac 上)或命令提示符(在 Windows 上)。然后，输入<code>go build</code>我们的文件名，然后按Enter。如果我们想运行一个名为 的文件<code>greet.go</code>，命令将如下所示：</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-dart" data-lang="dart">go build greet.go
</code></pre></div><p>虽然在我们运行我们的命令后没有任何明显的显示，但如果我们输入命令<code>ls</code>，我们将看到我们的原始 Go 程序和可执行文件。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-dart" data-lang="dart">ls
greet     greet.go
</code></pre></div><p>要执行文件，我们调用 <code>./greet</code></p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go">.<span style="color:#f92672">/</span><span style="color:#a6e22e">greet</span>
</code></pre></div><p>**注意：**如果 Go 编译器发现我们的 Go 代码没有正确编写，那么它会抛出错误并且我们的 Go 程序将无法编译。我们需要先修复错误，然后编译器才能正常工作。</p>
<p>现在，让我们<em>走</em>一步，真正做到这一点！</p>
<p>运行文件</p>
<p>太好了，我们能够将我们的程序编译成一个可执行文件，该文件将始终打印出“Hello World”。如果我们想让我们的程序再次运行，我们不必再次编译程序，我们只需运行可执行文件。因此，如果我们想要用户与之交互的快速代码，我们将编译一次程序并使用可执行文件。</p>
<p>但是如果我们想改变我们的程序会发生什么？我们必须编译另一个可执行文件，然后运行该文件。想象一下，为了检查一个小的更改或修复一个错误，每次都必须这样做！😱</p>
<p>值得庆幸的是，我们在<code>go run</code>命令后面加上了 Go 程序的名称。该<code>go run</code>命令为我们结合了代码的编译和执行。这使我们能够快速检查代码的输出(以及任何错误)。与 不同<code>go build</code>，<code>go run</code>不会在我们当前的文件夹中创建可执行文件。</p>
<p>基本 Go 结构：包</p>
<p>现在我们了解了如何编译和运行 Go 程序，让我们详细看看 Go 程序的结构，特别是它的包：</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span> 
 
<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span> 
 
<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span> () {
  <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;Hello World&#34;</span>) 
}
</code></pre></div><p>Go 程序是从上到下，从左到右阅读的，所以让我们关注第一行<code>package main</code>。这一行称为<em>包声明</em>，每个 Go 程序都以一个开头。包声明通知编译器是创建可执行文件还是<em>库</em>。与可执行文件相反，库不会直接运行/执行代码——它是可用于其他程序的代码集合。具有包声明的程序<code>package main</code>(如我们的)将创建一个可执行文件。</p>
<p>接下来是一个空行。Go 通常会忽略这些空行，它们被视为<em>空格</em>(新行、空格和制表符)。虽然我们的程序不需要换行符，但它使我们的代码更易于阅读，或者增加了程序的<em>可读性</em>。</p>
<p>然后我们有一个<em>导入语句</em>，<code>import &quot;fmt&quot;</code>。该<code>import</code>关键字允许我们从其他包中携带和使用的代码。我们还应该注意包名用双引号括起来<code>&quot;</code>，否则我们的程序会出错并且无法编译/运行。</p>
<p>包在 Go 中扮演着重要的角色。它们将相关代码组合在一起，允许代码可重用，并使其更易于维护。我们只导入我们需要的包。反过来，我们的程序运行得更快，因为它没有被额外的代码/包所困扰！</p>
<p>现在我们对如何编写 Go 程序有了一个大致的了解。让我们从头开始编写我们自己的！</p>
<p>每个 Go 程序都是由包构成的。</p>
<p>程序从 <code>main</code> 包开始运行。</p>
<p>本程序通过导入路径 <code>&quot;fmt&quot;</code> 和 <code>&quot;math/rand&quot;</code> 来使用这两个包。</p>
<p>按照约定，包名与导入路径的最后一个元素一致。例如，<code>&quot;math/rand&quot;</code> 包中的源码均以 <code>package rand</code> 语句开始。</p>
<p><em>注意：</em> 此程序的运行环境是固定的，因此 <code>rand.Intn</code> 总是会返回相同的数字。 (要得到不同的数字，需为生成器提供不同的种子数，参见 <a href="https://go-zh.org/pkg/math/rand/#Seed"><code>rand.Seed</code></a>。 练习场中的时间为常量，因此你需要用其它的值作为种子数。)</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;fmt&#34;</span>
	<span style="color:#e6db74">&#34;math/rand&#34;</span>
)

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;My favorite number is&#34;</span>, <span style="color:#a6e22e">rand</span>.<span style="color:#a6e22e">Intn</span>(<span style="color:#ae81ff">101</span>))
}

</code></pre></div><p>注释</p>
<p>我们不能总是亲自到场向下一个开发人员(甚至我们未来的自己)解释我们的代码做了什么或者我们在编写代码时的意图是什么。这就是评论的来源。</p>
<p>编译器会忽略注释，并且对很多事情都有帮助。我们可以使用注释来解释我们的代码或思考过程，甚至可以注释掉代码以进行<em>调试</em>(修复错误)。</p>
<p>Go 还鼓励使用注释来描述函数的作用，它被 Go 的文档工具使用。事实上，它始于他们的<a href="https://github.com/golang/go/wiki/Comments">Github Wiki 页面</a>！</p>
<p>Go 中有两种类型的注释。使用以下方法创建行注释<code>//</code>：</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#75715e">// This entire line is ignored by the compiler
</span><span style="color:#75715e">// fmt.Println(&#34;Does NOT print&#34;)
</span><span style="color:#75715e"></span><span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;This gets printed!&#34;</span>) <span style="color:#75715e">// This part gets ignored
</span></code></pre></div><p>请注意，该行注释掉了 右侧的内容<code>//</code>。</p>
<p>也有可以跨越多行的块注释——它以 开头<code>/*</code>，以 a 结尾，<code>*/</code>并包含其中的所有内容(包括新行)：</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#75715e">/*
</span><span style="color:#75715e">This is ignored.
</span><span style="color:#75715e">This is also ignored. 
</span><span style="color:#75715e">fmt.Println(&#34;This WON&#39;T print!&#34;)
</span><span style="color:#75715e">*/</span>
</code></pre></div><p>在上面的示例中，我们使用块注释注释掉了所有三行。</p>
<p>让我们在我们自己的代码中使用一些注释！</p>
<p>资源</p>
<p>学习 Go 这样的新语言需要学习相关的规则和语法。但是，我们不必将所有内容都提交到内存中！搜索一下就可以了，其实优秀的程序员都是这么干的！</p>
<p>如果你曾经被困在某件事上，请查看：</p>
<ul>
<li>Codecademy 的论坛
<ul>
<li>在此站点上查看学习者的问题和答案！</li>
</ul>
</li>
<li>Stack Overflow 的围棋问题
<ul>
<li>回答编程问题的程序员论坛。</li>
</ul>
</li>
<li>Go的官方网站
<ul>
<li>前往官方网站获取文档。</li>
</ul>
</li>
<li>谷歌
<ul>
<li>卷起袖子，搜索起来！</li>
<li>在某些情况下，搜索<strong>Golang</strong>而不是<strong>Go</strong>可能会有所帮助。</li>
</ul>
</li>
</ul>
<p>除了在线资源外，Go 还拥有自己的内置文档系统。要使用它，请在命令行中使用<code>go doc</code>后跟包名称的命令。例如，要查找有关<code>fmt</code>包的更多信息，可以使用以下命令：</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#66d9ef">go</span> <span style="color:#a6e22e">doc</span> <span style="color:#a6e22e">fmt</span> 
</code></pre></div><p>在终端中，您将在顶部看到：</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">fmt</span> <span style="color:#75715e">// import &#34;fmt&#34;
</span><span style="color:#75715e"></span> 
<span style="color:#a6e22e">Package</span> <span style="color:#a6e22e">fmt</span> <span style="color:#a6e22e">implements</span> <span style="color:#a6e22e">formatted</span> <span style="color:#a6e22e">I</span><span style="color:#f92672">/</span><span style="color:#a6e22e">O</span> <span style="color:#a6e22e">with</span> <span style="color:#a6e22e">functions</span> <span style="color:#a6e22e">analogous</span> <span style="color:#a6e22e">to</span> <span style="color:#a6e22e">C</span><span style="color:#960050;background-color:#1e0010">&#39;</span><span style="color:#a6e22e">s</span> <span style="color:#a6e22e">printf</span>
<span style="color:#a6e22e">and</span> <span style="color:#a6e22e">scanf</span>. <span style="color:#a6e22e">The</span> <span style="color:#a6e22e">format</span> <span style="color:#960050;background-color:#1e0010">&#39;</span><span style="color:#a6e22e">verbs</span><span style="color:#960050;background-color:#1e0010">&#39;</span> <span style="color:#a6e22e">are</span> <span style="color:#a6e22e">derived</span> <span style="color:#a6e22e">from</span> <span style="color:#a6e22e">C</span><span style="color:#960050;background-color:#1e0010">&#39;</span><span style="color:#a6e22e">s</span> <span style="color:#a6e22e">but</span> <span style="color:#a6e22e">are</span> <span style="color:#a6e22e">simpler</span>.
<span style="color:#f92672">...</span>
</code></pre></div><p>返回的信息实际上跨越了好几行，上面的例子被截断了。要获取有关包中函数的更多具体信息(如<code>fmt</code>的<code>Println</code>函数)，请将<code>.Println</code>(或<code>.println</code>，函数的大小写与 无关)附加<code>go doc</code>到命令：</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#66d9ef">go</span> <span style="color:#a6e22e">doc</span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>
</code></pre></div><p><code>go doc</code>当您与新的库和包进行交互时，该命令也非常有用。自己试试吧！</p>
<p>审查</p>
<p>很好！您刚刚完成了第一堂围棋课程！在本课中，您学到了：</p>
<ul>
<li>Go/Golang 是什么。</li>
<li>Go 的用途。</li>
<li>Go 的编译器。</li>
<li>如何将 Go 文件编译为可执行文件。</li>
<li>运行一个可执行文件。</li>
<li>运行 Go 文件而不直接编译它。</li>
<li>Go 包是什么。</li>
<li>如何导入 Go 包。</li>
<li>如何导入多个 Go 包。</li>
<li>包中<code>main</code>函数的唯一性<code>main</code>。</li>
<li>如何查找帮助和信息。</li>
</ul>
<p>进入一种新的奇幻语言的第一步是美妙旅程的开始。<em>走</em>多远由您决定。</p>
<p>如果您有兴趣设置您的计算机以在您自己的计算机上创建 Go 程序，请使用我们的<a href="https://www.codecademy.com/articles/setting-up-go-locally">本地开发 Go 指南</a>！</p>
<h2 id="命名返回值">命名返回值</h2>
<p>Go 的返回值可被命名，它们会被视作定义在函数顶部的变量。</p>
<p>返回值的名称应当具有一定的意义，它可以作为文档使用。</p>
<p>没有参数的 <code>return</code> 语句返回已命名的返回值。也就是 <code>直接</code> 返回。</p>
<p>直接返回语句应当仅用在下面这样的短函数中。在长的函数中它们会影响代码的可读性。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">split</span>(<span style="color:#a6e22e">sum</span> <span style="color:#66d9ef">int</span>) (<span style="color:#a6e22e">x</span>, <span style="color:#a6e22e">y</span> <span style="color:#66d9ef">int</span>) {
	<span style="color:#a6e22e">x</span> = <span style="color:#a6e22e">sum</span> <span style="color:#f92672">*</span> <span style="color:#ae81ff">4</span> <span style="color:#f92672">/</span> <span style="color:#ae81ff">9</span>
	<span style="color:#a6e22e">y</span> = <span style="color:#a6e22e">sum</span> <span style="color:#f92672">-</span> <span style="color:#a6e22e">x</span>
	<span style="color:#66d9ef">return</span>
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">split</span>(<span style="color:#ae81ff">17</span>))
}
<span style="color:#75715e">//7 10
</span></code></pre></div><h2 id="变量的初始化">变量的初始化</h2>
<p>变量声明可以包含初始值，每个变量对应一个。</p>
<p>如果初始化值已存在，则可以省略类型；变量会从初始值中获得类型。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">i</span>, <span style="color:#a6e22e">j</span> <span style="color:#66d9ef">int</span> = <span style="color:#ae81ff">1</span>, <span style="color:#ae81ff">2</span>

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">c</span>, <span style="color:#a6e22e">python</span>, <span style="color:#a6e22e">java</span> = <span style="color:#66d9ef">true</span>, <span style="color:#66d9ef">false</span>, <span style="color:#e6db74">&#34;no!&#34;</span>
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">i</span>, <span style="color:#a6e22e">j</span>, <span style="color:#a6e22e">c</span>, <span style="color:#a6e22e">python</span>, <span style="color:#a6e22e">java</span>)
}

</code></pre></div><h2 id="短变量声明">短变量声明</h2>
<p>在函数中，简洁赋值语句 <code>:=</code> 可在类型明确的地方代替 <code>var</code> 声明。</p>
<p>函数外的每个语句都必须以关键字开始(<code>var</code>, <code>func</code> 等等)，因此 <code>:=</code> 结构不能在函数外使用。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">i</span>, <span style="color:#a6e22e">j</span> <span style="color:#66d9ef">int</span> = <span style="color:#ae81ff">1</span>, <span style="color:#ae81ff">2</span>
	<span style="color:#a6e22e">k</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">3</span>
	<span style="color:#a6e22e">c</span>, <span style="color:#a6e22e">python</span>, <span style="color:#a6e22e">java</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">true</span>, <span style="color:#66d9ef">false</span>, <span style="color:#e6db74">&#34;no!&#34;</span>

	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">i</span>, <span style="color:#a6e22e">j</span>, <span style="color:#a6e22e">k</span>, <span style="color:#a6e22e">c</span>, <span style="color:#a6e22e">python</span>, <span style="color:#a6e22e">java</span>)
}

</code></pre></div><h2 id="基本类型">基本类型</h2>
<p>Go 的基本类型有</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#66d9ef">bool</span>

<span style="color:#66d9ef">string</span>

<span style="color:#66d9ef">int</span>  <span style="color:#66d9ef">int8</span>  <span style="color:#66d9ef">int16</span>  <span style="color:#66d9ef">int32</span>  <span style="color:#66d9ef">int64</span>
<span style="color:#66d9ef">uint</span> <span style="color:#66d9ef">uint8</span> <span style="color:#66d9ef">uint16</span> <span style="color:#66d9ef">uint32</span> <span style="color:#66d9ef">uint64</span> <span style="color:#66d9ef">uintptr</span>

<span style="color:#66d9ef">byte</span> <span style="color:#75715e">// uint8 的别名
</span><span style="color:#75715e"></span>
<span style="color:#66d9ef">rune</span> <span style="color:#75715e">// int32 的别名
</span><span style="color:#75715e"></span>    <span style="color:#75715e">// 表示一个 Unicode 码点
</span><span style="color:#75715e"></span>
<span style="color:#66d9ef">float32</span> <span style="color:#66d9ef">float64</span>

<span style="color:#66d9ef">complex64</span> <span style="color:#66d9ef">complex128</span>
</code></pre></div><p>本例展示了几种类型的变量。 同导入语句一样，变量声明也可以“分组”成一个语法块。</p>
<p><code>int</code>, <code>uint</code> 和 <code>uintptr</code> 在 32 位系统上通常为 32 位宽，在 64 位系统上则为 64 位宽。 当你需要一个整数值时应使用 <code>int</code> 类型，除非你有特殊的理由使用固定大小或无符号的整数类型。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;fmt&#34;</span>
	<span style="color:#e6db74">&#34;math/cmplx&#34;</span>
)

<span style="color:#66d9ef">var</span> (
	<span style="color:#a6e22e">ToBe</span>   <span style="color:#66d9ef">bool</span>       = <span style="color:#66d9ef">false</span>
	<span style="color:#a6e22e">MaxInt</span> <span style="color:#66d9ef">uint64</span>     = <span style="color:#ae81ff">1</span><span style="color:#f92672">&lt;&lt;</span><span style="color:#ae81ff">64</span> <span style="color:#f92672">-</span> <span style="color:#ae81ff">1</span>
	<span style="color:#a6e22e">z</span>      <span style="color:#66d9ef">complex128</span> = <span style="color:#a6e22e">cmplx</span>.<span style="color:#a6e22e">Sqrt</span>(<span style="color:#f92672">-</span><span style="color:#ae81ff">5</span> <span style="color:#f92672">+</span> <span style="color:#ae81ff">12i</span>)
)

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;Type: %T Value: %v\n&#34;</span>, <span style="color:#a6e22e">ToBe</span>, <span style="color:#a6e22e">ToBe</span>)
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;Type: %T Value: %v\n&#34;</span>, <span style="color:#a6e22e">MaxInt</span>, <span style="color:#a6e22e">MaxInt</span>)
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;Type: %T Value: %v\n&#34;</span>, <span style="color:#a6e22e">z</span>, <span style="color:#a6e22e">z</span>)
}

</code></pre></div><p>1</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#a6e22e">Type</span>: <span style="color:#66d9ef">bool</span> <span style="color:#a6e22e">Value</span>: <span style="color:#66d9ef">false</span>
<span style="color:#a6e22e">Type</span>: <span style="color:#66d9ef">uint64</span> <span style="color:#a6e22e">Value</span>: <span style="color:#ae81ff">18446744073709551615</span>
<span style="color:#a6e22e">Type</span>: <span style="color:#66d9ef">complex128</span> <span style="color:#a6e22e">Value</span>: (<span style="color:#ae81ff">2</span><span style="color:#f92672">+</span><span style="color:#ae81ff">3i</span>)
</code></pre></div><h2 id="零值">零值</h2>
<p>没有明确初始值的变量声明会被赋予它们的 <strong>零值</strong>。</p>
<p>零值是：</p>
<ul>
<li>数值类型为 <code>0</code>，</li>
<li>布尔类型为 <code>false</code>，</li>
<li>字符串为 <code>&quot;&quot;</code>(空字符串)。</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">i</span> <span style="color:#66d9ef">int</span>
	<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">f</span> <span style="color:#66d9ef">float64</span>
	<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">b</span> <span style="color:#66d9ef">bool</span>
	<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">s</span> <span style="color:#66d9ef">string</span>
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;%v %v %v %q\n&#34;</span>, <span style="color:#a6e22e">i</span>, <span style="color:#a6e22e">f</span>, <span style="color:#a6e22e">b</span>, <span style="color:#a6e22e">s</span>)
}

</code></pre></div><h2 id="类型转换">类型转换</h2>
<p>表达式 <code>T(v)</code> 将值 <code>v</code> 转换为类型 <code>T</code>。</p>
<p>一些关于数值的转换：</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#66d9ef">var</span> <span style="color:#a6e22e">i</span> <span style="color:#66d9ef">int</span> = <span style="color:#ae81ff">42</span>
<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">f</span> <span style="color:#66d9ef">float64</span> = float64(<span style="color:#a6e22e">i</span>)
<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">u</span> <span style="color:#66d9ef">uint</span> = uint(<span style="color:#a6e22e">f</span>)
</code></pre></div><p>或者，更加简单的形式：</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#a6e22e">i</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">42</span>
<span style="color:#a6e22e">f</span> <span style="color:#f92672">:=</span> float64(<span style="color:#a6e22e">i</span>)
<span style="color:#a6e22e">u</span> <span style="color:#f92672">:=</span> uint(<span style="color:#a6e22e">f</span>)
</code></pre></div><p>与 C 不同的是，Go 在不同类型的项之间赋值时需要显式转换。试着移除例子中 <code>float64</code> 或 <code>uint</code> 的转换看看会发生什么。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;fmt&#34;</span>
	<span style="color:#e6db74">&#34;math&#34;</span>
)

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">x</span>, <span style="color:#a6e22e">y</span> <span style="color:#66d9ef">int</span> = <span style="color:#ae81ff">3</span>, <span style="color:#ae81ff">4</span>
	<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">f</span> <span style="color:#66d9ef">float64</span> = <span style="color:#a6e22e">math</span>.<span style="color:#a6e22e">Sqrt</span>(float64(<span style="color:#a6e22e">x</span><span style="color:#f92672">*</span><span style="color:#a6e22e">x</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">y</span><span style="color:#f92672">*</span><span style="color:#a6e22e">y</span>))
	<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">z</span> <span style="color:#66d9ef">uint</span> = uint(<span style="color:#a6e22e">f</span>)
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">x</span>, <span style="color:#a6e22e">y</span>, <span style="color:#a6e22e">z</span>)
}

</code></pre></div><h2 id="类型推导">类型推导</h2>
<p>在声明一个变量而不指定其类型时(即使用不带类型的 <code>:=</code> 语法或 <code>var =</code> 表达式语法)，变量的类型由右值推导得出。</p>
<p>当右值声明了类型时，新变量的类型与其相同：</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#66d9ef">var</span> <span style="color:#a6e22e">i</span> <span style="color:#66d9ef">int</span>
<span style="color:#a6e22e">j</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">i</span> <span style="color:#75715e">// j 也是一个 int
</span></code></pre></div><p>不过当右边包含未指明类型的数值常量时，新变量的类型就可能是 <code>int</code>, <code>float64</code> 或 <code>complex128</code> 了，这取决于常量的精度：</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#a6e22e">i</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">42</span>           <span style="color:#75715e">// int
</span><span style="color:#75715e"></span><span style="color:#a6e22e">f</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">3.142</span>        <span style="color:#75715e">// float64
</span><span style="color:#75715e"></span><span style="color:#a6e22e">g</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">0.867</span> <span style="color:#f92672">+</span> <span style="color:#ae81ff">0.5i</span> <span style="color:#75715e">// complex128
</span></code></pre></div><p>尝试修改示例代码中 <code>v</code> 的初始值，并观察它是如何影响类型的。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">v</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">42</span> <span style="color:#75715e">// 修改这里！
</span><span style="color:#75715e"></span>	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;v is of type %T\n&#34;</span>, <span style="color:#a6e22e">v</span>)
}

</code></pre></div><h2 id="常量">常量</h2>
<p>常量的声明与变量类似，只不过是使用 <code>const</code> 关键字。</p>
<p>常量可以是字符、字符串、布尔值或数值。</p>
<p>常量不能用 <code>:=</code> 语法声明。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">const</span> <span style="color:#a6e22e">Pi</span> = <span style="color:#ae81ff">3.14</span>

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#66d9ef">const</span> <span style="color:#a6e22e">World</span> = <span style="color:#e6db74">&#34;世界&#34;</span>
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;Hello&#34;</span>, <span style="color:#a6e22e">World</span>)
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;Happy&#34;</span>, <span style="color:#a6e22e">Pi</span>, <span style="color:#e6db74">&#34;Day&#34;</span>)

	<span style="color:#66d9ef">const</span> <span style="color:#a6e22e">Truth</span> = <span style="color:#66d9ef">true</span>
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;Go rules?&#34;</span>, <span style="color:#a6e22e">Truth</span>)
}

</code></pre></div><h2 id="数值常量">数值常量</h2>
<p>数值常量是高精度的 <strong>值</strong>。</p>
<p>一个未指定类型的常量由上下文来决定其类型。</p>
<p>再尝试一下输出 <code>needInt(Big)</code> 吧。</p>
<p>(<code>int</code> 类型最大可以存储一个 64 位的整数，有时会更小。)</p>
<p>(<code>int</code> 可以存放最大64位的整数，根据平台不同有时会更少。)</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">const</span> (
	<span style="color:#75715e">// 将 1 左移 100 位来创建一个非常大的数字
</span><span style="color:#75715e"></span>	<span style="color:#75715e">// 即这个数的二进制是 1 后面跟着 100 个 0
</span><span style="color:#75715e"></span>	<span style="color:#a6e22e">Big</span> = <span style="color:#ae81ff">1</span> <span style="color:#f92672">&lt;&lt;</span> <span style="color:#ae81ff">100</span>
	<span style="color:#75715e">// 再往右移 99 位，即 Small = 1 &lt;&lt; 1，或者说 Small = 2
</span><span style="color:#75715e"></span>	<span style="color:#a6e22e">Small</span> = <span style="color:#a6e22e">Big</span> <span style="color:#f92672">&gt;&gt;</span> <span style="color:#ae81ff">99</span>
)

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">needInt</span>(<span style="color:#a6e22e">x</span> <span style="color:#66d9ef">int</span>) <span style="color:#66d9ef">int</span> { <span style="color:#66d9ef">return</span> <span style="color:#a6e22e">x</span><span style="color:#f92672">*</span><span style="color:#ae81ff">10</span> <span style="color:#f92672">+</span> <span style="color:#ae81ff">1</span> }
<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">needFloat</span>(<span style="color:#a6e22e">x</span> <span style="color:#66d9ef">float64</span>) <span style="color:#66d9ef">float64</span> {
	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">x</span> <span style="color:#f92672">*</span> <span style="color:#ae81ff">0.1</span>
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">needInt</span>(<span style="color:#a6e22e">Small</span>))
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">needFloat</span>(<span style="color:#a6e22e">Small</span>))
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">needFloat</span>(<span style="color:#a6e22e">Big</span>))
}

</code></pre></div><h2 id="for">for</h2>
<p>Go 只有一种循环结构：<code>for</code> 循环。</p>
<p>基本的 <code>for</code> 循环由三部分组成，它们用分号隔开：</p>
<ul>
<li>初始化语句：在第一次迭代前执行</li>
<li>条件表达式：在每次迭代前求值</li>
<li>后置语句：在每次迭代的结尾执行</li>
</ul>
<p>初始化语句通常为一句短变量声明，该变量声明仅在 <code>for</code> 语句的作用域中可见。</p>
<p>一旦条件表达式的布尔值为 <code>false</code>，循环迭代就会终止。</p>
<p><strong>注意</strong>：和 C、Java、JavaScript 之类的语言不同，Go 的 for 语句后面的三个构成部分外没有小括号， 大括号 <code>{ }</code> 则是必须的。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">sum</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">0</span>
	<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">i</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">0</span>; <span style="color:#a6e22e">i</span> &lt; <span style="color:#ae81ff">10</span>; <span style="color:#a6e22e">i</span><span style="color:#f92672">++</span> {
		<span style="color:#a6e22e">sum</span> <span style="color:#f92672">+=</span> <span style="color:#a6e22e">i</span>
	}
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">sum</span>)
}

</code></pre></div><h2 id="for续">for(续)</h2>
<p>初始化语句和后置语句是可选的。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">sum</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">1</span>
	<span style="color:#66d9ef">for</span> ; <span style="color:#a6e22e">sum</span> &lt; <span style="color:#ae81ff">1000</span>; {
		<span style="color:#a6e22e">sum</span> <span style="color:#f92672">+=</span> <span style="color:#a6e22e">sum</span>
	}
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">sum</span>)
}

</code></pre></div><h2 id="for-是-go-中的-while">for 是 Go 中的 “while”</h2>
<p>此时你可以去掉分号，因为 C 的 <code>while</code> 在 Go 中叫做 <code>for</code>。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">sum</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">1</span>
	<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">sum</span> &lt; <span style="color:#ae81ff">1000</span> {
		<span style="color:#a6e22e">sum</span> <span style="color:#f92672">+=</span> <span style="color:#a6e22e">sum</span>
	}
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">sum</span>)
}

</code></pre></div><h2 id="无限循环">无限循环</h2>
<p>如果省略循环条件，该循环就不会结束，因此无限循环可以写得很紧凑。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#66d9ef">for</span> {
	}
}

</code></pre></div><h2 id="if">if</h2>
<p>Go 的 <code>if</code> 语句与 <code>for</code> 循环类似，表达式外无需小括号 <code>( )</code> ，而大括号 <code>{ }</code> 则是必须的。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;fmt&#34;</span>
	<span style="color:#e6db74">&#34;math&#34;</span>
)

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">sqrt</span>(<span style="color:#a6e22e">x</span> <span style="color:#66d9ef">float64</span>) <span style="color:#66d9ef">string</span> {
	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">x</span> &lt; <span style="color:#ae81ff">0</span> {
		<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">sqrt</span>(<span style="color:#f92672">-</span><span style="color:#a6e22e">x</span>) <span style="color:#f92672">+</span> <span style="color:#e6db74">&#34;i&#34;</span>
	}
	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Sprint</span>(<span style="color:#a6e22e">math</span>.<span style="color:#a6e22e">Sqrt</span>(<span style="color:#a6e22e">x</span>))
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">sqrt</span>(<span style="color:#ae81ff">2</span>), <span style="color:#a6e22e">sqrt</span>(<span style="color:#f92672">-</span><span style="color:#ae81ff">4</span>))
}

</code></pre></div><h2 id="if-的简短语句">if 的简短语句</h2>
<p>同 <code>for</code> 一样， <code>if</code> 语句可以在条件表达式前执行一个简单的语句。</p>
<p>该语句声明的变量作用域仅在 <code>if</code> 之内。</p>
<p>(在最后的 <code>return</code> 语句处使用 <code>v</code> 看看。)</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;fmt&#34;</span>
	<span style="color:#e6db74">&#34;math&#34;</span>
)

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">pow</span>(<span style="color:#a6e22e">x</span>, <span style="color:#a6e22e">n</span>, <span style="color:#a6e22e">lim</span> <span style="color:#66d9ef">float64</span>) <span style="color:#66d9ef">float64</span> {
	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">v</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">math</span>.<span style="color:#a6e22e">Pow</span>(<span style="color:#a6e22e">x</span>, <span style="color:#a6e22e">n</span>); <span style="color:#a6e22e">v</span> &lt; <span style="color:#a6e22e">lim</span> {
		<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">v</span>
	}
	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">lim</span>
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(
		<span style="color:#a6e22e">pow</span>(<span style="color:#ae81ff">3</span>, <span style="color:#ae81ff">2</span>, <span style="color:#ae81ff">10</span>),
		<span style="color:#a6e22e">pow</span>(<span style="color:#ae81ff">3</span>, <span style="color:#ae81ff">3</span>, <span style="color:#ae81ff">20</span>),
	)
}

</code></pre></div><h2 id="if-和-else">if 和 else</h2>
<p>在 <code>if</code> 的简短语句中声明的变量同样可以在任何对应的 <code>else</code> 块中使用。</p>
<p>(在 <code>main</code> 的 <code>fmt.Println</code> 调用开始前，两次对 <code>pow</code> 的调用均已执行并返回其各自的结果。)</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;fmt&#34;</span>
	<span style="color:#e6db74">&#34;math&#34;</span>
)

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">pow</span>(<span style="color:#a6e22e">x</span>, <span style="color:#a6e22e">n</span>, <span style="color:#a6e22e">lim</span> <span style="color:#66d9ef">float64</span>) <span style="color:#66d9ef">float64</span> {
	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">v</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">math</span>.<span style="color:#a6e22e">Pow</span>(<span style="color:#a6e22e">x</span>, <span style="color:#a6e22e">n</span>); <span style="color:#a6e22e">v</span> &lt; <span style="color:#a6e22e">lim</span> {
		<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">v</span>
	} <span style="color:#66d9ef">else</span> {
		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;%g &gt;= %g\n&#34;</span>, <span style="color:#a6e22e">v</span>, <span style="color:#a6e22e">lim</span>)
	}
	<span style="color:#75715e">// 这里开始就不能使用 v 了
</span><span style="color:#75715e"></span>	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">lim</span>
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(
		<span style="color:#a6e22e">pow</span>(<span style="color:#ae81ff">3</span>, <span style="color:#ae81ff">2</span>, <span style="color:#ae81ff">10</span>),
		<span style="color:#a6e22e">pow</span>(<span style="color:#ae81ff">3</span>, <span style="color:#ae81ff">3</span>, <span style="color:#ae81ff">20</span>),
	)
}

</code></pre></div><h2 id="练习循环与函数">练习：循环与函数</h2>
<p>为了练习函数与循环，我们来实现一个平方根函数：用牛顿法实现平方根函数。</p>
<p>计算机通常使用循环来计算 x 的平方根。从某个猜测的值 z 开始，我们可以根据 z² 与 x 的近似度来调整 z，产生一个更好的猜测：</p>
<pre><code>z -= (z*z - x) / (2*z)
</code></pre><p>重复调整的过程，猜测的结果会越来越精确，得到的答案也会尽可能接近实际的平方根。</p>
<p>在提供的 <code>func Sqrt</code> 中实现它。无论输入是什么，对 z 的一个恰当的猜测为 1。 要开始，请重复计算 10 次并随之打印每次的 z 值。观察对于不同的值 x(1、2、3 &hellip;)， 你得到的答案是如何逼近结果的，猜测提升的速度有多快。</p>
<p>提示：用类型转换或浮点数语法来声明并初始化一个浮点数值：</p>
<pre><code>z := 1.0
z := float64(1)
</code></pre><p>然后，修改循环条件，使得当值停止改变(或改变非常小)的时候退出循环。观察迭代次数大于还是小于 10。 尝试改变 z 的初始猜测，如 x 或 x/2。你的函数结果与标准库中的 <a href="https://go-zh.org/pkg/math/#Sqrt">math.Sqrt</a> 接近吗？</p>
<p>(<em>注：</em> 如果你对该算法的细节感兴趣，上面的 z² − x 是 z² 到它所要到达的值(即 x)的距离， 除以的 2z 为 z² 的导数，我们通过 z² 的变化速度来改变 z 的调整量。 这种通用方法叫做<a href="https://zh.wikipedia.org/wiki/%E7%89%9B%E9%A1%BF%E6%B3%95">牛顿法</a>。 它对很多函数，特别是平方根而言非常有效。)</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;fmt&#34;</span>
)

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">Sqrt</span>(<span style="color:#a6e22e">x</span> <span style="color:#66d9ef">float64</span>) <span style="color:#66d9ef">float64</span> {
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">Sqrt</span>(<span style="color:#ae81ff">2</span>))
}

</code></pre></div><h2 id="switch">switch</h2>
<p><code>switch</code> 是编写一连串 <code>if - else</code> 语句的简便方法。它运行第一个值等于条件表达式的 case 语句。</p>
<p>Go 的 switch 语句类似于 C、C++、Java、JavaScript 和 PHP 中的，不过 Go 只运行选定的 case，而非之后所有的 case。 实际上，Go 自动提供了在这些语言中每个 case 后面所需的 <code>break</code> 语句。 除非以 <code>fallthrough</code> 语句结束，否则分支会自动终止。 Go 的另一点重要的不同在于 switch 的 case 无需为常量，且取值不必为整数。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;fmt&#34;</span>
	<span style="color:#e6db74">&#34;runtime&#34;</span>
)

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Print</span>(<span style="color:#e6db74">&#34;Go runs on &#34;</span>)
	<span style="color:#66d9ef">switch</span> <span style="color:#a6e22e">os</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">runtime</span>.<span style="color:#a6e22e">GOOS</span>; <span style="color:#a6e22e">os</span> {
	<span style="color:#66d9ef">case</span> <span style="color:#e6db74">&#34;darwin&#34;</span>:
		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;OS X.&#34;</span>)
	<span style="color:#66d9ef">case</span> <span style="color:#e6db74">&#34;linux&#34;</span>:
		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;Linux.&#34;</span>)
	<span style="color:#66d9ef">default</span>:
		<span style="color:#75715e">// freebsd, openbsd,
</span><span style="color:#75715e"></span>		<span style="color:#75715e">// plan9, windows...
</span><span style="color:#75715e"></span>		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;%s.\n&#34;</span>, <span style="color:#a6e22e">os</span>)
	}
}

</code></pre></div><h2 id="switch-的求值顺序">switch 的求值顺序</h2>
<p>switch 的 case 语句从上到下顺次执行，直到匹配成功时停止。</p>
<p>(例如，</p>
<pre><code>switch i {
case 0:
case f():
}
</code></pre><p>在 <code>i==0</code> 时 <code>f</code> 不会被调用。)</p>
<p><em>注意：</em> Go 练习场中的时间总是从 2009-11-10 23:00:00 UTC 开始，该值的意义留给读者去发现。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;fmt&#34;</span>
	<span style="color:#e6db74">&#34;time&#34;</span>
)

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;When&#39;s Saturday?&#34;</span>)
	<span style="color:#a6e22e">today</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Now</span>().<span style="color:#a6e22e">Weekday</span>()
	<span style="color:#66d9ef">switch</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Saturday</span> {
	<span style="color:#66d9ef">case</span> <span style="color:#a6e22e">today</span> <span style="color:#f92672">+</span> <span style="color:#ae81ff">0</span>:
		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;Today.&#34;</span>)
	<span style="color:#66d9ef">case</span> <span style="color:#a6e22e">today</span> <span style="color:#f92672">+</span> <span style="color:#ae81ff">1</span>:
		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;Tomorrow.&#34;</span>)
	<span style="color:#66d9ef">case</span> <span style="color:#a6e22e">today</span> <span style="color:#f92672">+</span> <span style="color:#ae81ff">2</span>:
		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;In two days.&#34;</span>)
	<span style="color:#66d9ef">default</span>:
		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;Too far away.&#34;</span>)
	}
}

</code></pre></div><h2 id="没有条件的-switch">没有条件的 switch</h2>
<p>没有条件的 switch 同 <code>switch true</code> 一样。</p>
<p>这种形式能将一长串 if-then-else 写得更加清晰。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;fmt&#34;</span>
	<span style="color:#e6db74">&#34;time&#34;</span>
)

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">t</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Now</span>()
	<span style="color:#66d9ef">switch</span> {
	<span style="color:#66d9ef">case</span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Hour</span>() &lt; <span style="color:#ae81ff">12</span>:
		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;Good morning!&#34;</span>)
	<span style="color:#66d9ef">case</span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Hour</span>() &lt; <span style="color:#ae81ff">17</span>:
		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;Good afternoon.&#34;</span>)
	<span style="color:#66d9ef">default</span>:
		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;Good evening.&#34;</span>)
	}
}

</code></pre></div><h2 id="defer">defer</h2>
<p>defer 语句会将函数推迟到外层函数返回之后执行。</p>
<p>推迟调用的函数其参数会立即求值，但直到外层函数返回前该函数都不会被调用。。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#66d9ef">defer</span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;world&#34;</span>)

	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;hello&#34;</span>)
}

</code></pre></div><h2 id="defer-栈">defer 栈</h2>
<p>推迟的函数调用会被压入一个栈中。当外层函数返回时，被推迟的函数会按照后进先出的顺序调用。</p>
<p>更多关于 defer 语句的信息，请阅读<a href="http://blog.go-zh.org/defer-panic-and-recover">此博文</a>。。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;counting&#34;</span>)

	<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">i</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">0</span>; <span style="color:#a6e22e">i</span> &lt; <span style="color:#ae81ff">10</span>; <span style="color:#a6e22e">i</span><span style="color:#f92672">++</span> {
		<span style="color:#66d9ef">defer</span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">i</span>)
	}

	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;done&#34;</span>)
}

</code></pre></div><h2 id="指针">指针</h2>
<p>Go 拥有指针。指针保存了值的内存地址。</p>
<p>类型 <code>*T</code> 是指向 <code>T</code> 类型值的指针。其零值为 <code>nil</code>。</p>
<pre><code>var p *int
</code></pre><p><code>&amp;</code> 操作符会生成一个指向其操作数的指针。</p>
<pre><code>i := 42
p = &amp;i
</code></pre><p><code>*</code> 操作符表示指针指向的底层值。</p>
<pre><code>fmt.Println(*p) // 通过指针 p 读取 i
*p = 21         // 通过指针 p 设置 i
</code></pre><p>这也就是通常所说的“间接引用”或“重定向”。</p>
<p>与 C 不同，Go 没有指针运算。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">i</span>, <span style="color:#a6e22e">j</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">42</span>, <span style="color:#ae81ff">2701</span>

	<span style="color:#a6e22e">p</span> <span style="color:#f92672">:=</span> <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">i</span>         <span style="color:#75715e">// 指向 i
</span><span style="color:#75715e"></span>	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#f92672">*</span><span style="color:#a6e22e">p</span>) <span style="color:#75715e">// 通过指针读取 i 的值
</span><span style="color:#75715e"></span>	<span style="color:#f92672">*</span><span style="color:#a6e22e">p</span> = <span style="color:#ae81ff">21</span>         <span style="color:#75715e">// 通过指针设置 i 的值
</span><span style="color:#75715e"></span>	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">i</span>)  <span style="color:#75715e">// 查看 i 的值
</span><span style="color:#75715e"></span>
	<span style="color:#a6e22e">p</span> = <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">j</span>         <span style="color:#75715e">// 指向 j
</span><span style="color:#75715e"></span>	<span style="color:#f92672">*</span><span style="color:#a6e22e">p</span> = <span style="color:#f92672">*</span><span style="color:#a6e22e">p</span> <span style="color:#f92672">/</span> <span style="color:#ae81ff">37</span>   <span style="color:#75715e">// 通过指针对 j 进行除法运算
</span><span style="color:#75715e"></span>	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">j</span>) <span style="color:#75715e">// 查看 j 的值
</span><span style="color:#75715e"></span>}

</code></pre></div><h2 id="结构体">结构体</h2>
<p>一个结构体(<code>struct</code>)就是一组字段(field)。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Vertex</span> <span style="color:#66d9ef">struct</span> {
	<span style="color:#a6e22e">X</span> <span style="color:#66d9ef">int</span>
	<span style="color:#a6e22e">Y</span> <span style="color:#66d9ef">int</span>
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">Vertex</span>{<span style="color:#ae81ff">1</span>, <span style="color:#ae81ff">2</span>})
}

</code></pre></div><h2 id="结构体字段">结构体字段</h2>
<p>结构体字段使用点号来访问。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Vertex</span> <span style="color:#66d9ef">struct</span> {
	<span style="color:#a6e22e">X</span> <span style="color:#66d9ef">int</span>
	<span style="color:#a6e22e">Y</span> <span style="color:#66d9ef">int</span>
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">v</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">Vertex</span>{<span style="color:#ae81ff">1</span>, <span style="color:#ae81ff">2</span>}
	<span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">X</span> = <span style="color:#ae81ff">4</span>
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">X</span>)
}

</code></pre></div><h2 id="结构体指针">结构体指针</h2>
<p>结构体字段可以通过结构体指针来访问。</p>
<p>如果我们有一个指向结构体的指针 <code>p</code>，那么可以通过 <code>(*p).X</code> 来访问其字段 <code>X</code>。不过这么写太啰嗦了，所以语言也允许我们使用隐式间接引用，直接写 <code>p.X</code> 就可以。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Vertex</span> <span style="color:#66d9ef">struct</span> {
	<span style="color:#a6e22e">X</span> <span style="color:#66d9ef">int</span>
	<span style="color:#a6e22e">Y</span> <span style="color:#66d9ef">int</span>
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">v</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">Vertex</span>{<span style="color:#ae81ff">1</span>, <span style="color:#ae81ff">2</span>}
	<span style="color:#a6e22e">p</span> <span style="color:#f92672">:=</span> <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">v</span>
	<span style="color:#a6e22e">p</span>.<span style="color:#a6e22e">X</span> = <span style="color:#ae81ff">1e9</span>
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">v</span>)
}

</code></pre></div><h2 id="结构体文法">结构体文法</h2>
<p>结构体文法通过直接列出字段的值来新分配一个结构体。</p>
<p>使用 <code>Name:</code> 语法可以仅列出部分字段。(字段名的顺序无关。)</p>
<p>特殊的前缀 <code>&amp;</code> 返回一个指向结构体的指针。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Vertex</span> <span style="color:#66d9ef">struct</span> {
	<span style="color:#a6e22e">X</span>, <span style="color:#a6e22e">Y</span> <span style="color:#66d9ef">int</span>
}

<span style="color:#66d9ef">var</span> (
	<span style="color:#a6e22e">v1</span> = <span style="color:#a6e22e">Vertex</span>{<span style="color:#ae81ff">1</span>, <span style="color:#ae81ff">2</span>}  <span style="color:#75715e">// 创建一个 Vertex 类型的结构体
</span><span style="color:#75715e"></span>	<span style="color:#a6e22e">v2</span> = <span style="color:#a6e22e">Vertex</span>{<span style="color:#a6e22e">X</span>: <span style="color:#ae81ff">1</span>}  <span style="color:#75715e">// Y:0 被隐式地赋予
</span><span style="color:#75715e"></span>	<span style="color:#a6e22e">v3</span> = <span style="color:#a6e22e">Vertex</span>{}      <span style="color:#75715e">// X:0 Y:0
</span><span style="color:#75715e"></span>	<span style="color:#a6e22e">p</span>  = <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">Vertex</span>{<span style="color:#ae81ff">1</span>, <span style="color:#ae81ff">2</span>} <span style="color:#75715e">// 创建一个 *Vertex 类型的结构体(指针)
</span><span style="color:#75715e"></span>)

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">v1</span>, <span style="color:#a6e22e">p</span>, <span style="color:#a6e22e">v2</span>, <span style="color:#a6e22e">v3</span>)
}

</code></pre></div><h2 id="数组">数组</h2>
<p>类型 <code>[n]T</code> 表示拥有 <code>n</code> 个 <code>T</code> 类型的值的数组。</p>
<p>表达式</p>
<pre><code>var a [10]int
</code></pre><p>会将变量 <code>a</code> 声明为拥有 10 个整数的数组。</p>
<p>数组的长度是其类型的一部分，因此数组不能改变大小。这看起来是个限制，不过没关系，Go 提供了更加便利的方式来使用数组。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">a</span> [<span style="color:#ae81ff">2</span>]<span style="color:#66d9ef">string</span>
	<span style="color:#a6e22e">a</span>[<span style="color:#ae81ff">0</span>] = <span style="color:#e6db74">&#34;Hello&#34;</span>
	<span style="color:#a6e22e">a</span>[<span style="color:#ae81ff">1</span>] = <span style="color:#e6db74">&#34;World&#34;</span>
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">a</span>[<span style="color:#ae81ff">0</span>], <span style="color:#a6e22e">a</span>[<span style="color:#ae81ff">1</span>])
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">a</span>)

	<span style="color:#a6e22e">primes</span> <span style="color:#f92672">:=</span> [<span style="color:#ae81ff">6</span>]<span style="color:#66d9ef">int</span>{<span style="color:#ae81ff">2</span>, <span style="color:#ae81ff">3</span>, <span style="color:#ae81ff">5</span>, <span style="color:#ae81ff">7</span>, <span style="color:#ae81ff">11</span>, <span style="color:#ae81ff">13</span>}
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">primes</span>)
}

</code></pre></div><h2 id="切片">切片</h2>
<p>每个数组的大小都是固定的。而切片则为数组元素提供动态大小的、灵活的视角。在实践中，切片比数组更常用。</p>
<p>类型 <code>[]T</code> 表示一个元素类型为 <code>T</code> 的切片。</p>
<p>切片通过两个下标来界定，即一个上界和一个下界，二者以冒号分隔：</p>
<pre><code>a[low : high]
</code></pre><p>它会选择一个半开区间，包括第一个元素，但排除最后一个元素。</p>
<p>以下表达式创建了一个切片，它包含 <code>a</code> 中下标从 1 到 3 的元素：</p>
<pre><code>a[1:4]
</code></pre><div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">primes</span> <span style="color:#f92672">:=</span> [<span style="color:#ae81ff">6</span>]<span style="color:#66d9ef">int</span>{<span style="color:#ae81ff">2</span>, <span style="color:#ae81ff">3</span>, <span style="color:#ae81ff">5</span>, <span style="color:#ae81ff">7</span>, <span style="color:#ae81ff">11</span>, <span style="color:#ae81ff">13</span>}

	<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">s</span> []<span style="color:#66d9ef">int</span> = <span style="color:#a6e22e">primes</span>[<span style="color:#ae81ff">1</span>:<span style="color:#ae81ff">4</span>]
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">s</span>)
}

</code></pre></div><p>1本例展示了几种类型的变量。 同导入语句一样，变量声明也可以“分组”成一个语法块。</p>
<p><code>int</code>, <code>uint</code> 和 <code>uintptr</code> 在 32 位系统上通常为 32 位宽，在 64 位系统上则为 64 位宽。 当你需要一个整数值时应使用 <code>int</code> 类型，除非你有特殊的理由使用固定大小或无符号的整数类型。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;fmt&#34;</span>
	<span style="color:#e6db74">&#34;math/cmplx&#34;</span>
)

<span style="color:#66d9ef">var</span> (
	<span style="color:#a6e22e">ToBe</span>   <span style="color:#66d9ef">bool</span>       = <span style="color:#66d9ef">false</span>
	<span style="color:#a6e22e">MaxInt</span> <span style="color:#66d9ef">uint64</span>     = <span style="color:#ae81ff">1</span><span style="color:#f92672">&lt;&lt;</span><span style="color:#ae81ff">64</span> <span style="color:#f92672">-</span> <span style="color:#ae81ff">1</span>
	<span style="color:#a6e22e">z</span>      <span style="color:#66d9ef">complex128</span> = <span style="color:#a6e22e">cmplx</span>.<span style="color:#a6e22e">Sqrt</span>(<span style="color:#f92672">-</span><span style="color:#ae81ff">5</span> <span style="color:#f92672">+</span> <span style="color:#ae81ff">12i</span>)
)

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;Type: %T Value: %v\n&#34;</span>, <span style="color:#a6e22e">ToBe</span>, <span style="color:#a6e22e">ToBe</span>)
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;Type: %T Value: %v\n&#34;</span>, <span style="color:#a6e22e">MaxInt</span>, <span style="color:#a6e22e">MaxInt</span>)
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;Type: %T Value: %v\n&#34;</span>, <span style="color:#a6e22e">z</span>, <span style="color:#a6e22e">z</span>)
}

</code></pre></div><h2 id="切片就像数组的引用">切片就像数组的引用</h2>
<p>切片并不存储任何数据，它只是描述了底层数组中的一段。</p>
<p>更改切片的元素会修改其底层数组中对应的元素。</p>
<p>与它共享底层数组的切片都会观测到这些修改。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">names</span> <span style="color:#f92672">:=</span> [<span style="color:#ae81ff">4</span>]<span style="color:#66d9ef">string</span>{
		<span style="color:#e6db74">&#34;John&#34;</span>,
		<span style="color:#e6db74">&#34;Paul&#34;</span>,
		<span style="color:#e6db74">&#34;George&#34;</span>,
		<span style="color:#e6db74">&#34;Ringo&#34;</span>,
	}
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">names</span>)

	<span style="color:#a6e22e">a</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">names</span>[<span style="color:#ae81ff">0</span>:<span style="color:#ae81ff">2</span>]
	<span style="color:#a6e22e">b</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">names</span>[<span style="color:#ae81ff">1</span>:<span style="color:#ae81ff">3</span>]
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">a</span>, <span style="color:#a6e22e">b</span>)

	<span style="color:#a6e22e">b</span>[<span style="color:#ae81ff">0</span>] = <span style="color:#e6db74">&#34;XXX&#34;</span>
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">a</span>, <span style="color:#a6e22e">b</span>)
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">names</span>)
}

</code></pre></div><h2 id="切片文法">切片文法</h2>
<p>切片文法类似于没有长度的数组文法。</p>
<p>这是一个数组文法：</p>
<pre><code>[3]bool{true, true, false}
</code></pre><p>下面这样则会创建一个和上面相同的数组，然后构建一个引用了它的切片：</p>
<pre><code>[]bool{true, true, false}
</code></pre><div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">q</span> <span style="color:#f92672">:=</span> []<span style="color:#66d9ef">int</span>{<span style="color:#ae81ff">2</span>, <span style="color:#ae81ff">3</span>, <span style="color:#ae81ff">5</span>, <span style="color:#ae81ff">7</span>, <span style="color:#ae81ff">11</span>, <span style="color:#ae81ff">13</span>}
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">q</span>)

	<span style="color:#a6e22e">r</span> <span style="color:#f92672">:=</span> []<span style="color:#66d9ef">bool</span>{<span style="color:#66d9ef">true</span>, <span style="color:#66d9ef">false</span>, <span style="color:#66d9ef">true</span>, <span style="color:#66d9ef">true</span>, <span style="color:#66d9ef">false</span>, <span style="color:#66d9ef">true</span>}
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">r</span>)

	<span style="color:#a6e22e">s</span> <span style="color:#f92672">:=</span> []<span style="color:#66d9ef">struct</span> {
		<span style="color:#a6e22e">i</span> <span style="color:#66d9ef">int</span>
		<span style="color:#a6e22e">b</span> <span style="color:#66d9ef">bool</span>
	}{
		{<span style="color:#ae81ff">2</span>, <span style="color:#66d9ef">true</span>},
		{<span style="color:#ae81ff">3</span>, <span style="color:#66d9ef">false</span>},
		{<span style="color:#ae81ff">5</span>, <span style="color:#66d9ef">true</span>},
		{<span style="color:#ae81ff">7</span>, <span style="color:#66d9ef">true</span>},
		{<span style="color:#ae81ff">11</span>, <span style="color:#66d9ef">false</span>},
		{<span style="color:#ae81ff">13</span>, <span style="color:#66d9ef">true</span>},
	}
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">s</span>)
}

</code></pre></div><h2 id="切片的默认行为">切片的默认行为</h2>
<p>在进行切片时，你可以利用它的默认行为来忽略上下界。</p>
<p>切片下界的默认值为 <code>0</code>，上界则是该切片的长度。</p>
<p>对于数组</p>
<pre><code>var a [10]int
</code></pre><p>来说，以下切片是等价的：</p>
<pre><code>a[0:10]
a[:10]
a[0:]
a[:]
</code></pre><div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">s</span> <span style="color:#f92672">:=</span> []<span style="color:#66d9ef">int</span>{<span style="color:#ae81ff">2</span>, <span style="color:#ae81ff">3</span>, <span style="color:#ae81ff">5</span>, <span style="color:#ae81ff">7</span>, <span style="color:#ae81ff">11</span>, <span style="color:#ae81ff">13</span>}

	<span style="color:#a6e22e">s</span> = <span style="color:#a6e22e">s</span>[<span style="color:#ae81ff">1</span>:<span style="color:#ae81ff">4</span>]
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">s</span>)

	<span style="color:#a6e22e">s</span> = <span style="color:#a6e22e">s</span>[:<span style="color:#ae81ff">2</span>]
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">s</span>)

	<span style="color:#a6e22e">s</span> = <span style="color:#a6e22e">s</span>[<span style="color:#ae81ff">1</span>:]
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">s</span>)
}

</code></pre></div><h2 id="切片的长度与容量">切片的长度与容量</h2>
<p>切片拥有 <strong>长度</strong> 和 <strong>容量</strong>。</p>
<p>切片的长度就是它所包含的元素个数。</p>
<p>切片的容量是从它的第一个元素开始数，到其底层数组元素末尾的个数。</p>
<p>切片 <code>s</code> 的长度和容量可通过表达式 <code>len(s)</code> 和 <code>cap(s)</code> 来获取。</p>
<p>你可以通过重新切片来扩展一个切片，给它提供足够的容量。试着修改示例程序中的切片操作，向外扩展它的容量，看看会发生什么。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">s</span> <span style="color:#f92672">:=</span> []<span style="color:#66d9ef">int</span>{<span style="color:#ae81ff">2</span>, <span style="color:#ae81ff">3</span>, <span style="color:#ae81ff">5</span>, <span style="color:#ae81ff">7</span>, <span style="color:#ae81ff">11</span>, <span style="color:#ae81ff">13</span>}
	<span style="color:#a6e22e">printSlice</span>(<span style="color:#a6e22e">s</span>)

	<span style="color:#75715e">// 截取切片使其长度为 0
</span><span style="color:#75715e"></span>	<span style="color:#a6e22e">s</span> = <span style="color:#a6e22e">s</span>[:<span style="color:#ae81ff">0</span>]
	<span style="color:#a6e22e">printSlice</span>(<span style="color:#a6e22e">s</span>)

	<span style="color:#75715e">// 拓展其长度
</span><span style="color:#75715e"></span>	<span style="color:#a6e22e">s</span> = <span style="color:#a6e22e">s</span>[:<span style="color:#ae81ff">4</span>]
	<span style="color:#a6e22e">printSlice</span>(<span style="color:#a6e22e">s</span>)

	<span style="color:#75715e">// 舍弃前两个值
</span><span style="color:#75715e"></span>	<span style="color:#a6e22e">s</span> = <span style="color:#a6e22e">s</span>[<span style="color:#ae81ff">2</span>:]
	<span style="color:#a6e22e">printSlice</span>(<span style="color:#a6e22e">s</span>)
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">printSlice</span>(<span style="color:#a6e22e">s</span> []<span style="color:#66d9ef">int</span>) {
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;len=%d cap=%d %v\n&#34;</span>, len(<span style="color:#a6e22e">s</span>), cap(<span style="color:#a6e22e">s</span>), <span style="color:#a6e22e">s</span>)
}

</code></pre></div><h2 id="nil-切片">nil 切片</h2>
<p>切片的零值是 <code>nil</code>。</p>
<p>nil 切片的长度和容量为 0 且没有底层数组。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">s</span> []<span style="color:#66d9ef">int</span>
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">s</span>, len(<span style="color:#a6e22e">s</span>), cap(<span style="color:#a6e22e">s</span>))
	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">s</span> <span style="color:#f92672">==</span> <span style="color:#66d9ef">nil</span> {
		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;nil!&#34;</span>)
	}
}

</code></pre></div><h2 id="用-make-创建切片">用 make 创建切片</h2>
<p>切片可以用内建函数 <code>make</code> 来创建，这也是你创建动态数组的方式。</p>
<p><code>make</code> 函数会分配一个元素为零值的数组并返回一个引用了它的切片：</p>
<pre><code>a := make([]int, 5)  // len(a)=5
</code></pre><p>要指定它的容量，需向 <code>make</code> 传入第三个参数：</p>
<pre><code>b := make([]int, 0, 5) // len(b)=0, cap(b)=5

b = b[:cap(b)] // len(b)=5, cap(b)=5
b = b[1:]      // len(b)=4, cap(b)=4
</code></pre><div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">a</span> <span style="color:#f92672">:=</span> make([]<span style="color:#66d9ef">int</span>, <span style="color:#ae81ff">5</span>)
	<span style="color:#a6e22e">printSlice</span>(<span style="color:#e6db74">&#34;a&#34;</span>, <span style="color:#a6e22e">a</span>)

	<span style="color:#a6e22e">b</span> <span style="color:#f92672">:=</span> make([]<span style="color:#66d9ef">int</span>, <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">5</span>)
	<span style="color:#a6e22e">printSlice</span>(<span style="color:#e6db74">&#34;b&#34;</span>, <span style="color:#a6e22e">b</span>)

	<span style="color:#a6e22e">c</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">b</span>[:<span style="color:#ae81ff">2</span>]
	<span style="color:#a6e22e">printSlice</span>(<span style="color:#e6db74">&#34;c&#34;</span>, <span style="color:#a6e22e">c</span>)

	<span style="color:#a6e22e">d</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">c</span>[<span style="color:#ae81ff">2</span>:<span style="color:#ae81ff">5</span>]
	<span style="color:#a6e22e">printSlice</span>(<span style="color:#e6db74">&#34;d&#34;</span>, <span style="color:#a6e22e">d</span>)
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">printSlice</span>(<span style="color:#a6e22e">s</span> <span style="color:#66d9ef">string</span>, <span style="color:#a6e22e">x</span> []<span style="color:#66d9ef">int</span>) {
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;%s len=%d cap=%d %v\n&#34;</span>,
		<span style="color:#a6e22e">s</span>, len(<span style="color:#a6e22e">x</span>), cap(<span style="color:#a6e22e">x</span>), <span style="color:#a6e22e">x</span>)
}

</code></pre></div><h2 id="切片的切片">切片的切片</h2>
<p>切片可包含任何类型，甚至包括其它的切片。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;fmt&#34;</span>
	<span style="color:#e6db74">&#34;strings&#34;</span>
)

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#75715e">// 创建一个井字板(经典游戏)
</span><span style="color:#75715e"></span>	<span style="color:#a6e22e">board</span> <span style="color:#f92672">:=</span> [][]<span style="color:#66d9ef">string</span>{
		[]<span style="color:#66d9ef">string</span>{<span style="color:#e6db74">&#34;_&#34;</span>, <span style="color:#e6db74">&#34;_&#34;</span>, <span style="color:#e6db74">&#34;_&#34;</span>},
		[]<span style="color:#66d9ef">string</span>{<span style="color:#e6db74">&#34;_&#34;</span>, <span style="color:#e6db74">&#34;_&#34;</span>, <span style="color:#e6db74">&#34;_&#34;</span>},
		[]<span style="color:#66d9ef">string</span>{<span style="color:#e6db74">&#34;_&#34;</span>, <span style="color:#e6db74">&#34;_&#34;</span>, <span style="color:#e6db74">&#34;_&#34;</span>},
	}

	<span style="color:#75715e">// 两个玩家轮流打上 X 和 O
</span><span style="color:#75715e"></span>	<span style="color:#a6e22e">board</span>[<span style="color:#ae81ff">0</span>][<span style="color:#ae81ff">0</span>] = <span style="color:#e6db74">&#34;X&#34;</span>
	<span style="color:#a6e22e">board</span>[<span style="color:#ae81ff">2</span>][<span style="color:#ae81ff">2</span>] = <span style="color:#e6db74">&#34;O&#34;</span>
	<span style="color:#a6e22e">board</span>[<span style="color:#ae81ff">1</span>][<span style="color:#ae81ff">2</span>] = <span style="color:#e6db74">&#34;X&#34;</span>
	<span style="color:#a6e22e">board</span>[<span style="color:#ae81ff">1</span>][<span style="color:#ae81ff">0</span>] = <span style="color:#e6db74">&#34;O&#34;</span>
	<span style="color:#a6e22e">board</span>[<span style="color:#ae81ff">0</span>][<span style="color:#ae81ff">2</span>] = <span style="color:#e6db74">&#34;X&#34;</span>

	<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">i</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">0</span>; <span style="color:#a6e22e">i</span> &lt; len(<span style="color:#a6e22e">board</span>); <span style="color:#a6e22e">i</span><span style="color:#f92672">++</span> {
		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;%s\n&#34;</span>, <span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">Join</span>(<span style="color:#a6e22e">board</span>[<span style="color:#a6e22e">i</span>], <span style="color:#e6db74">&#34; &#34;</span>))
	}
}

</code></pre></div><h2 id="向切片追加元素">向切片追加元素</h2>
<p>为切片追加新的元素是种常用的操作，为此 Go 提供了内建的 <code>append</code> 函数。内建函数的<a href="https://go-zh.org/pkg/builtin/#append">文档</a>对此函数有详细的介绍。</p>
<pre><code>func append(s []T, vs ...T) []T
</code></pre><p><code>append</code> 的第一个参数 <code>s</code> 是一个元素类型为 <code>T</code> 的切片，其余类型为 <code>T</code> 的值将会追加到该切片的末尾。</p>
<p><code>append</code> 的结果是一个包含原切片所有元素加上新添加元素的切片。</p>
<p>当 <code>s</code> 的底层数组太小，不足以容纳所有给定的值时，它就会分配一个更大的数组。返回的切片会指向这个新分配的数组。</p>
<p>(要了解关于切片的更多内容，请阅读文章 <a href="https://blog.go-zh.org/go-slices-usage-and-internals">Go 切片：用法和本质</a>。)</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">s</span> []<span style="color:#66d9ef">int</span>
	<span style="color:#a6e22e">printSlice</span>(<span style="color:#a6e22e">s</span>)

	<span style="color:#75715e">// 添加一个空切片
</span><span style="color:#75715e"></span>	<span style="color:#a6e22e">s</span> = append(<span style="color:#a6e22e">s</span>, <span style="color:#ae81ff">0</span>)
	<span style="color:#a6e22e">printSlice</span>(<span style="color:#a6e22e">s</span>)

	<span style="color:#75715e">// 这个切片会按需增长
</span><span style="color:#75715e"></span>	<span style="color:#a6e22e">s</span> = append(<span style="color:#a6e22e">s</span>, <span style="color:#ae81ff">1</span>)
	<span style="color:#a6e22e">printSlice</span>(<span style="color:#a6e22e">s</span>)

	<span style="color:#75715e">// 可以一次性添加多个元素
</span><span style="color:#75715e"></span>	<span style="color:#a6e22e">s</span> = append(<span style="color:#a6e22e">s</span>, <span style="color:#ae81ff">2</span>, <span style="color:#ae81ff">3</span>, <span style="color:#ae81ff">4</span>)
	<span style="color:#a6e22e">printSlice</span>(<span style="color:#a6e22e">s</span>)
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">printSlice</span>(<span style="color:#a6e22e">s</span> []<span style="color:#66d9ef">int</span>) {
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;len=%d cap=%d %v\n&#34;</span>, len(<span style="color:#a6e22e">s</span>), cap(<span style="color:#a6e22e">s</span>), <span style="color:#a6e22e">s</span>)
}

</code></pre></div><h2 id="range">Range</h2>
<p><code>for</code> 循环的 <code>range</code> 形式可遍历切片或映射。</p>
<p>当使用 <code>for</code> 循环遍历切片时，每次迭代都会返回两个值。第一个值为当前元素的下标，第二个值为该下标所对应元素的一份副本。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">pow</span> = []<span style="color:#66d9ef">int</span>{<span style="color:#ae81ff">1</span>, <span style="color:#ae81ff">2</span>, <span style="color:#ae81ff">4</span>, <span style="color:#ae81ff">8</span>, <span style="color:#ae81ff">16</span>, <span style="color:#ae81ff">32</span>, <span style="color:#ae81ff">64</span>, <span style="color:#ae81ff">128</span>}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">i</span>, <span style="color:#a6e22e">v</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">pow</span> {
		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;2**%d = %d\n&#34;</span>, <span style="color:#a6e22e">i</span>, <span style="color:#a6e22e">v</span>)
	}
}

</code></pre></div><h2 id="range续">range(续)</h2>
<p>可以将下标或值赋予 <code>_</code> 来忽略它。</p>
<pre><code>for i, _ := range pow
for _, value := range pow
</code></pre><p>若你只需要索引，忽略第二个变量即可。</p>
<pre><code>for i := range pow
</code></pre><div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">pow</span> <span style="color:#f92672">:=</span> make([]<span style="color:#66d9ef">int</span>, <span style="color:#ae81ff">10</span>)
	<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">i</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">pow</span> {
		<span style="color:#a6e22e">pow</span>[<span style="color:#a6e22e">i</span>] = <span style="color:#ae81ff">1</span> <span style="color:#f92672">&lt;&lt;</span> uint(<span style="color:#a6e22e">i</span>) <span style="color:#75715e">// == 2**i
</span><span style="color:#75715e"></span>	}
	<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">value</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">pow</span> {
		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;%d\n&#34;</span>, <span style="color:#a6e22e">value</span>)
	}
}

</code></pre></div><h2 id="练习切片">练习：切片</h2>
<p>实现 <code>Pic</code>。它应当返回一个长度为 <code>dy</code> 的切片，其中每个元素是一个长度为 <code>dx</code>，元素类型为 <code>uint8</code> 的切片。当你运行此程序时，它会将每个整数解释为灰度值(好吧，其实是蓝度值)并显示它所对应的图像。</p>
<p>图像的选择由你来定。几个有趣的函数包括 <code>(x+y)/2</code>, <code>x*y</code>, <code>x^y</code>, <code>x*log(y)</code> 和 <code>x%(y+1)</code>。</p>
<p>(提示：需要使用循环来分配 <code>[][]uint8</code> 中的每个 <code>[]uint8</code>；请使用 <code>uint8(intValue)</code> 在类型之间转换；你可能会用到 <code>math</code> 包中的函数。)</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;golang.org/x/tour/pic&#34;</span>

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">Pic</span>(<span style="color:#a6e22e">dx</span>, <span style="color:#a6e22e">dy</span> <span style="color:#66d9ef">int</span>) [][]<span style="color:#66d9ef">uint8</span> {
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">pic</span>.<span style="color:#a6e22e">Show</span>(<span style="color:#a6e22e">Pic</span>)
}
</code></pre></div><h2 id="映射">映射</h2>
<p>映射将键映射到值。</p>
<p>映射的零值为 <code>nil</code> 。<code>nil</code> 映射既没有键，也不能添加键。</p>
<p><code>make</code> 函数会返回给定类型的映射，并将其初始化备用。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Vertex</span> <span style="color:#66d9ef">struct</span> {
	<span style="color:#a6e22e">Lat</span>, <span style="color:#a6e22e">Long</span> <span style="color:#66d9ef">float64</span>
}

<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">m</span> <span style="color:#66d9ef">map</span>[<span style="color:#66d9ef">string</span>]<span style="color:#a6e22e">Vertex</span>

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">m</span> = make(<span style="color:#66d9ef">map</span>[<span style="color:#66d9ef">string</span>]<span style="color:#a6e22e">Vertex</span>)
	<span style="color:#a6e22e">m</span>[<span style="color:#e6db74">&#34;Bell Labs&#34;</span>] = <span style="color:#a6e22e">Vertex</span>{
		<span style="color:#ae81ff">40.68433</span>, <span style="color:#f92672">-</span><span style="color:#ae81ff">74.39967</span>,
	}
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">m</span>[<span style="color:#e6db74">&#34;Bell Labs&#34;</span>])
}

</code></pre></div><h2 id="映射的文法">映射的文法</h2>
<p>映射的文法与结构体相似，不过必须有键名。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Vertex</span> <span style="color:#66d9ef">struct</span> {
	<span style="color:#a6e22e">Lat</span>, <span style="color:#a6e22e">Long</span> <span style="color:#66d9ef">float64</span>
}

<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">m</span> = <span style="color:#66d9ef">map</span>[<span style="color:#66d9ef">string</span>]<span style="color:#a6e22e">Vertex</span>{
	<span style="color:#e6db74">&#34;Bell Labs&#34;</span>: <span style="color:#a6e22e">Vertex</span>{
		<span style="color:#ae81ff">40.68433</span>, <span style="color:#f92672">-</span><span style="color:#ae81ff">74.39967</span>,
	},
	<span style="color:#e6db74">&#34;Google&#34;</span>: <span style="color:#a6e22e">Vertex</span>{
		<span style="color:#ae81ff">37.42202</span>, <span style="color:#f92672">-</span><span style="color:#ae81ff">122.08408</span>,
	},
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">m</span>)
}

</code></pre></div><h2 id="映射的文法续">映射的文法(续)</h2>
<p>若顶级类型只是一个类型名，你可以在文法的元素中省略它。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Vertex</span> <span style="color:#66d9ef">struct</span> {
	<span style="color:#a6e22e">Lat</span>, <span style="color:#a6e22e">Long</span> <span style="color:#66d9ef">float64</span>
}

<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">m</span> = <span style="color:#66d9ef">map</span>[<span style="color:#66d9ef">string</span>]<span style="color:#a6e22e">Vertex</span>{
	<span style="color:#e6db74">&#34;Bell Labs&#34;</span>: {<span style="color:#ae81ff">40.68433</span>, <span style="color:#f92672">-</span><span style="color:#ae81ff">74.39967</span>},
	<span style="color:#e6db74">&#34;Google&#34;</span>:    {<span style="color:#ae81ff">37.42202</span>, <span style="color:#f92672">-</span><span style="color:#ae81ff">122.08408</span>},
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">m</span>)
}

</code></pre></div><h2 id="修改映射">修改映射</h2>
<p>在映射 <code>m</code> 中插入或修改元素：</p>
<pre><code>m[key] = elem
</code></pre><p>获取元素：</p>
<pre><code>elem = m[key]
</code></pre><p>删除元素：</p>
<pre><code>delete(m, key)
</code></pre><p>通过双赋值检测某个键是否存在：</p>
<pre><code>elem, ok = m[key]
</code></pre><p>若 <code>key</code> 在 <code>m</code> 中，<code>ok</code> 为 <code>true</code> ；否则，<code>ok</code> 为 <code>false</code>。</p>
<p>若 <code>key</code> 不在映射中，那么 <code>elem</code> 是该映射元素类型的零值。</p>
<p>同样的，当从映射中读取某个不存在的键时，结果是映射的元素类型的零值。</p>
<p><strong>注</strong> ：若 <code>elem</code> 或 <code>ok</code> 还未声明，你可以使用短变量声明：</p>
<pre><code>elem, ok := m[key]
</code></pre><div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">m</span> <span style="color:#f92672">:=</span> make(<span style="color:#66d9ef">map</span>[<span style="color:#66d9ef">string</span>]<span style="color:#66d9ef">int</span>)

	<span style="color:#a6e22e">m</span>[<span style="color:#e6db74">&#34;Answer&#34;</span>] = <span style="color:#ae81ff">42</span>
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;The value:&#34;</span>, <span style="color:#a6e22e">m</span>[<span style="color:#e6db74">&#34;Answer&#34;</span>])

	<span style="color:#a6e22e">m</span>[<span style="color:#e6db74">&#34;Answer&#34;</span>] = <span style="color:#ae81ff">48</span>
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;The value:&#34;</span>, <span style="color:#a6e22e">m</span>[<span style="color:#e6db74">&#34;Answer&#34;</span>])

	delete(<span style="color:#a6e22e">m</span>, <span style="color:#e6db74">&#34;Answer&#34;</span>)
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;The value:&#34;</span>, <span style="color:#a6e22e">m</span>[<span style="color:#e6db74">&#34;Answer&#34;</span>])

	<span style="color:#a6e22e">v</span>, <span style="color:#a6e22e">ok</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">m</span>[<span style="color:#e6db74">&#34;Answer&#34;</span>]
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;The value:&#34;</span>, <span style="color:#a6e22e">v</span>, <span style="color:#e6db74">&#34;Present?&#34;</span>, <span style="color:#a6e22e">ok</span>)
}

</code></pre></div><h2 id="练习映射">练习：映射</h2>
<p>实现 <code>WordCount</code>。它应当返回一个映射，其中包含字符串 <code>s</code> 中每个“单词”的个数。函数 <code>wc.Test</code> 会对此函数执行一系列测试用例，并输出成功还是失败。</p>
<p>你会发现 <a href="https://go-zh.org/pkg/strings/#Fields">strings.Fields</a> 很有帮助。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;golang.org/x/tour/wc&#34;</span>
)

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">WordCount</span>(<span style="color:#a6e22e">s</span> <span style="color:#66d9ef">string</span>) <span style="color:#66d9ef">map</span>[<span style="color:#66d9ef">string</span>]<span style="color:#66d9ef">int</span> {
	<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">map</span>[<span style="color:#66d9ef">string</span>]<span style="color:#66d9ef">int</span>{<span style="color:#e6db74">&#34;x&#34;</span>: <span style="color:#ae81ff">1</span>}
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">wc</span>.<span style="color:#a6e22e">Test</span>(<span style="color:#a6e22e">WordCount</span>)
}

</code></pre></div><h2 id="函数值">函数值</h2>
<p>函数也是值。它们可以像其它值一样传递。</p>
<p>函数值可以用作函数的参数或返回值。。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;fmt&#34;</span>
	<span style="color:#e6db74">&#34;math&#34;</span>
)

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">compute</span>(<span style="color:#a6e22e">fn</span> <span style="color:#66d9ef">func</span>(<span style="color:#66d9ef">float64</span>, <span style="color:#66d9ef">float64</span>) <span style="color:#66d9ef">float64</span>) <span style="color:#66d9ef">float64</span> {
	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">fn</span>(<span style="color:#ae81ff">3</span>, <span style="color:#ae81ff">4</span>)
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">hypot</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">x</span>, <span style="color:#a6e22e">y</span> <span style="color:#66d9ef">float64</span>) <span style="color:#66d9ef">float64</span> {
		<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">math</span>.<span style="color:#a6e22e">Sqrt</span>(<span style="color:#a6e22e">x</span><span style="color:#f92672">*</span><span style="color:#a6e22e">x</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">y</span><span style="color:#f92672">*</span><span style="color:#a6e22e">y</span>)
	}
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">hypot</span>(<span style="color:#ae81ff">5</span>, <span style="color:#ae81ff">12</span>))

	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">compute</span>(<span style="color:#a6e22e">hypot</span>))
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">compute</span>(<span style="color:#a6e22e">math</span>.<span style="color:#a6e22e">Pow</span>))
}

</code></pre></div><h2 id="函数的闭包">函数的闭包</h2>
<p>Go 函数可以是一个闭包。闭包是一个函数值，它引用了其函数体之外的变量。该函数可以访问并赋予其引用的变量的值，换句话说，该函数被这些变量“绑定”在一起。</p>
<p>例如，函数 <code>adder</code> 返回一个闭包。每个闭包都被绑定在其各自的 <code>sum</code> 变量上。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">adder</span>() <span style="color:#66d9ef">func</span>(<span style="color:#66d9ef">int</span>) <span style="color:#66d9ef">int</span> {
	<span style="color:#a6e22e">sum</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">0</span>
	<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">x</span> <span style="color:#66d9ef">int</span>) <span style="color:#66d9ef">int</span> {
		<span style="color:#a6e22e">sum</span> <span style="color:#f92672">+=</span> <span style="color:#a6e22e">x</span>
		<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">sum</span>
	}
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">pos</span>, <span style="color:#a6e22e">neg</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">adder</span>(), <span style="color:#a6e22e">adder</span>()
	<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">i</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">0</span>; <span style="color:#a6e22e">i</span> &lt; <span style="color:#ae81ff">10</span>; <span style="color:#a6e22e">i</span><span style="color:#f92672">++</span> {
		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(
			<span style="color:#a6e22e">pos</span>(<span style="color:#a6e22e">i</span>),
			<span style="color:#a6e22e">neg</span>(<span style="color:#f92672">-</span><span style="color:#ae81ff">2</span><span style="color:#f92672">*</span><span style="color:#a6e22e">i</span>),
		)
	}
}

</code></pre></div><h2 id="练习斐波纳契闭包">练习：斐波纳契闭包</h2>
<p>让我们用函数做些好玩的事情。</p>
<p>实现一个 <code>fibonacci</code> 函数，它返回一个函数(闭包)，该闭包返回一个<a href="https://zh.wikipedia.org/wiki/%E6%96%90%E6%B3%A2%E9%82%A3%E5%A5%91%E6%95%B0%E5%88%97">斐波纳契数列</a> <code>(0, 1, 1, 2, 3, 5, ...)</code>。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#75715e">// 返回一个“返回int的函数”
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">fibonacci</span>() <span style="color:#66d9ef">func</span>() <span style="color:#66d9ef">int</span> {
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">f</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">fibonacci</span>()
	<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">i</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">0</span>; <span style="color:#a6e22e">i</span> &lt; <span style="color:#ae81ff">10</span>; <span style="color:#a6e22e">i</span><span style="color:#f92672">++</span> {
		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">f</span>())
	}
}

</code></pre></div><h2 id="方法">方法</h2>
<p>Go 没有类。不过你可以为结构体类型定义方法。</p>
<p>方法就是一类带特殊的 <strong>接收者</strong> 参数的函数。</p>
<p>方法接收者在它自己的参数列表内，位于 <code>func</code> 关键字和方法名之间。</p>
<p>在此例中，<code>Abs</code> 方法拥有一个名为 <code>v</code>，类型为 <code>Vertex</code> 的接收者。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;fmt&#34;</span>
	<span style="color:#e6db74">&#34;math&#34;</span>
)

<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Vertex</span> <span style="color:#66d9ef">struct</span> {
	<span style="color:#a6e22e">X</span>, <span style="color:#a6e22e">Y</span> <span style="color:#66d9ef">float64</span>
}

<span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">v</span> <span style="color:#a6e22e">Vertex</span>) <span style="color:#a6e22e">Abs</span>() <span style="color:#66d9ef">float64</span> {
	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">math</span>.<span style="color:#a6e22e">Sqrt</span>(<span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">X</span><span style="color:#f92672">*</span><span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">X</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Y</span><span style="color:#f92672">*</span><span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Y</span>)
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">v</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">Vertex</span>{<span style="color:#ae81ff">3</span>, <span style="color:#ae81ff">4</span>}
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Abs</span>())
}

</code></pre></div><h2 id="方法即函数">方法即函数</h2>
<p>记住：方法只是个带接收者参数的函数。</p>
<p>现在这个 <code>Abs</code> 的写法就是个正常的函数，功能并没有什么变化。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;fmt&#34;</span>
	<span style="color:#e6db74">&#34;math&#34;</span>
)

<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Vertex</span> <span style="color:#66d9ef">struct</span> {
	<span style="color:#a6e22e">X</span>, <span style="color:#a6e22e">Y</span> <span style="color:#66d9ef">float64</span>
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">Abs</span>(<span style="color:#a6e22e">v</span> <span style="color:#a6e22e">Vertex</span>) <span style="color:#66d9ef">float64</span> {
	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">math</span>.<span style="color:#a6e22e">Sqrt</span>(<span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">X</span><span style="color:#f92672">*</span><span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">X</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Y</span><span style="color:#f92672">*</span><span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Y</span>)
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">v</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">Vertex</span>{<span style="color:#ae81ff">3</span>, <span style="color:#ae81ff">4</span>}
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">Abs</span>(<span style="color:#a6e22e">v</span>))
}

</code></pre></div><h2 id="方法续">方法(续)</h2>
<p>你也可以为非结构体类型声明方法。</p>
<p>在此例中，我们看到了一个带 <code>Abs</code> 方法的数值类型 <code>MyFloat</code>。</p>
<p>你只能为在同一包内定义的类型的接收者声明方法，而不能为其它包内定义的类型(包括 <code>int</code> 之类的内建类型)的接收者声明方法。</p>
<p>(译注：就是接收者的类型定义和方法声明必须在同一包内；不能为内建类型声明方法。)</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;fmt&#34;</span>
	<span style="color:#e6db74">&#34;math&#34;</span>
)

<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">MyFloat</span> <span style="color:#66d9ef">float64</span>

<span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">f</span> <span style="color:#a6e22e">MyFloat</span>) <span style="color:#a6e22e">Abs</span>() <span style="color:#66d9ef">float64</span> {
	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">f</span> &lt; <span style="color:#ae81ff">0</span> {
		<span style="color:#66d9ef">return</span> float64(<span style="color:#f92672">-</span><span style="color:#a6e22e">f</span>)
	}
	<span style="color:#66d9ef">return</span> float64(<span style="color:#a6e22e">f</span>)
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">f</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">MyFloat</span>(<span style="color:#f92672">-</span><span style="color:#a6e22e">math</span>.<span style="color:#a6e22e">Sqrt2</span>)
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">f</span>.<span style="color:#a6e22e">Abs</span>())
}

</code></pre></div><h2 id="指针接收者">指针接收者</h2>
<p>你可以为指针接收者声明方法。</p>
<p>这意味着对于某类型 <code>T</code>，接收者的类型可以用 <code>*T</code> 的文法。(此外，<code>T</code> 不能是像 <code>*int</code> 这样的指针。)</p>
<p>例如，这里为 <code>*Vertex</code> 定义了 <code>Scale</code> 方法。</p>
<p>指针接收者的方法可以修改接收者指向的值(就像 <code>Scale</code> 在这做的)。由于方法经常需要修改它的接收者，指针接收者比值接收者更常用。</p>
<p>试着移除第 16 行 <code>Scale</code> 函数声明中的 <code>*</code>，观察此程序的行为如何变化。</p>
<p>若使用值接收者，那么 <code>Scale</code> 方法会对原始 <code>Vertex</code> 值的副本进行操作。(对于函数的其它参数也是如此。)<code>Scale</code> 方法必须用指针接受者来更改 <code>main</code> 函数中声明的 <code>Vertex</code> 的值。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;fmt&#34;</span>
	<span style="color:#e6db74">&#34;math&#34;</span>
)

<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Vertex</span> <span style="color:#66d9ef">struct</span> {
	<span style="color:#a6e22e">X</span>, <span style="color:#a6e22e">Y</span> <span style="color:#66d9ef">float64</span>
}

<span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">v</span> <span style="color:#a6e22e">Vertex</span>) <span style="color:#a6e22e">Abs</span>() <span style="color:#66d9ef">float64</span> {
	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">math</span>.<span style="color:#a6e22e">Sqrt</span>(<span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">X</span><span style="color:#f92672">*</span><span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">X</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Y</span><span style="color:#f92672">*</span><span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Y</span>)
}

<span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">v</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">Vertex</span>) <span style="color:#a6e22e">Scale</span>(<span style="color:#a6e22e">f</span> <span style="color:#66d9ef">float64</span>) {
	<span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">X</span> = <span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">X</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">f</span>
	<span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Y</span> = <span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Y</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">f</span>
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">v</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">Vertex</span>{<span style="color:#ae81ff">3</span>, <span style="color:#ae81ff">4</span>}
	<span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Scale</span>(<span style="color:#ae81ff">10</span>)
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Abs</span>())
}

</code></pre></div><h2 id="指针与函数">指针与函数</h2>
<p>现在我们要把 <code>Abs</code> 和 <code>Scale</code> 方法重写为函数。</p>
<p>同样，我们先试着移除掉第 16 的 <code>*</code>。你能看出为什么程序的行为改变了吗？要怎样做才能让该示例顺利通过编译？</p>
<p>(若你不确定，继续往下看。)</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;fmt&#34;</span>
	<span style="color:#e6db74">&#34;math&#34;</span>
)

<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Vertex</span> <span style="color:#66d9ef">struct</span> {
	<span style="color:#a6e22e">X</span>, <span style="color:#a6e22e">Y</span> <span style="color:#66d9ef">float64</span>
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">Abs</span>(<span style="color:#a6e22e">v</span> <span style="color:#a6e22e">Vertex</span>) <span style="color:#66d9ef">float64</span> {
	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">math</span>.<span style="color:#a6e22e">Sqrt</span>(<span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">X</span><span style="color:#f92672">*</span><span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">X</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Y</span><span style="color:#f92672">*</span><span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Y</span>)
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">Scale</span>(<span style="color:#a6e22e">v</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">Vertex</span>, <span style="color:#a6e22e">f</span> <span style="color:#66d9ef">float64</span>) {
	<span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">X</span> = <span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">X</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">f</span>
	<span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Y</span> = <span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Y</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">f</span>
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">v</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">Vertex</span>{<span style="color:#ae81ff">3</span>, <span style="color:#ae81ff">4</span>}
	<span style="color:#a6e22e">Scale</span>(<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">v</span>, <span style="color:#ae81ff">10</span>)
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">Abs</span>(<span style="color:#a6e22e">v</span>))
}

</code></pre></div><h2 id="方法与指针重定向">方法与指针重定向</h2>
<p>比较前两个程序，你大概会注意到带指针参数的函数必须接受一个指针：</p>
<pre><code>var v Vertex
ScaleFunc(v, 5)  // 编译错误！
ScaleFunc(&amp;v, 5) // OK
</code></pre><p>而以指针为接收者的方法被调用时，接收者既能为值又能为指针：</p>
<pre><code>var v Vertex
v.Scale(5)  // OK
p := &amp;v
p.Scale(10) // OK
</code></pre><p>对于语句 <code>v.Scale(5)</code>，即便 <code>v</code> 是个值而非指针，带指针接收者的方法也能被直接调用。 也就是说，由于 <code>Scale</code> 方法有一个指针接收者，为方便起见，Go 会将语句 <code>v.Scale(5)</code> 解释为 <code>(&amp;v).Scale(5)</code>。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Vertex</span> <span style="color:#66d9ef">struct</span> {
	<span style="color:#a6e22e">X</span>, <span style="color:#a6e22e">Y</span> <span style="color:#66d9ef">float64</span>
}

<span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">v</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">Vertex</span>) <span style="color:#a6e22e">Scale</span>(<span style="color:#a6e22e">f</span> <span style="color:#66d9ef">float64</span>) {
	<span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">X</span> = <span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">X</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">f</span>
	<span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Y</span> = <span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Y</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">f</span>
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">ScaleFunc</span>(<span style="color:#a6e22e">v</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">Vertex</span>, <span style="color:#a6e22e">f</span> <span style="color:#66d9ef">float64</span>) {
	<span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">X</span> = <span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">X</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">f</span>
	<span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Y</span> = <span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Y</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">f</span>
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">v</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">Vertex</span>{<span style="color:#ae81ff">3</span>, <span style="color:#ae81ff">4</span>}
	<span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Scale</span>(<span style="color:#ae81ff">2</span>)
	<span style="color:#a6e22e">ScaleFunc</span>(<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">v</span>, <span style="color:#ae81ff">10</span>)

	<span style="color:#a6e22e">p</span> <span style="color:#f92672">:=</span> <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">Vertex</span>{<span style="color:#ae81ff">4</span>, <span style="color:#ae81ff">3</span>}
	<span style="color:#a6e22e">p</span>.<span style="color:#a6e22e">Scale</span>(<span style="color:#ae81ff">3</span>)
	<span style="color:#a6e22e">ScaleFunc</span>(<span style="color:#a6e22e">p</span>, <span style="color:#ae81ff">8</span>)

	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">v</span>, <span style="color:#a6e22e">p</span>)
}

</code></pre></div><h2 id="方法与指针重定向续">方法与指针重定向(续)</h2>
<p>同样的事情也发生在相反的方向。</p>
<p>接受一个值作为参数的函数必须接受一个指定类型的值：</p>
<pre><code>var v Vertex
fmt.Println(AbsFunc(v))  // OK
fmt.Println(AbsFunc(&amp;v)) // 编译错误！
</code></pre><p>而以值为接收者的方法被调用时，接收者既能为值又能为指针：</p>
<pre><code>var v Vertex
fmt.Println(v.Abs()) // OK
p := &amp;v
fmt.Println(p.Abs()) // OK
</code></pre><p>这种情况下，方法调用 <code>p.Abs()</code> 会被解释为 <code>(*p).Abs()</code>。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;fmt&#34;</span>
	<span style="color:#e6db74">&#34;math&#34;</span>
)

<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Vertex</span> <span style="color:#66d9ef">struct</span> {
	<span style="color:#a6e22e">X</span>, <span style="color:#a6e22e">Y</span> <span style="color:#66d9ef">float64</span>
}

<span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">v</span> <span style="color:#a6e22e">Vertex</span>) <span style="color:#a6e22e">Abs</span>() <span style="color:#66d9ef">float64</span> {
	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">math</span>.<span style="color:#a6e22e">Sqrt</span>(<span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">X</span><span style="color:#f92672">*</span><span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">X</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Y</span><span style="color:#f92672">*</span><span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Y</span>)
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">AbsFunc</span>(<span style="color:#a6e22e">v</span> <span style="color:#a6e22e">Vertex</span>) <span style="color:#66d9ef">float64</span> {
	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">math</span>.<span style="color:#a6e22e">Sqrt</span>(<span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">X</span><span style="color:#f92672">*</span><span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">X</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Y</span><span style="color:#f92672">*</span><span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Y</span>)
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">v</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">Vertex</span>{<span style="color:#ae81ff">3</span>, <span style="color:#ae81ff">4</span>}
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Abs</span>())
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">AbsFunc</span>(<span style="color:#a6e22e">v</span>))

	<span style="color:#a6e22e">p</span> <span style="color:#f92672">:=</span> <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">Vertex</span>{<span style="color:#ae81ff">4</span>, <span style="color:#ae81ff">3</span>}
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">p</span>.<span style="color:#a6e22e">Abs</span>())
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">AbsFunc</span>(<span style="color:#f92672">*</span><span style="color:#a6e22e">p</span>))
}

</code></pre></div><h2 id="选择值或指针作为接收者">选择值或指针作为接收者</h2>
<p>使用指针接收者的原因有二：</p>
<p>首先，方法能够修改其接收者指向的值。</p>
<p>其次，这样可以避免在每次调用方法时复制该值。若值的类型为大型结构体时，这样做会更加高效。</p>
<p>在本例中，<code>Scale</code> 和 <code>Abs</code> 接收者的类型为 <code>*Vertex</code>，即便 <code>Abs</code> 并不需要修改其接收者。</p>
<p>通常来说，所有给定类型的方法都应该有值或指针接收者，但并不应该二者混用。(我们会在接下来几页中明白为什么。)</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;fmt&#34;</span>
	<span style="color:#e6db74">&#34;math&#34;</span>
)

<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Vertex</span> <span style="color:#66d9ef">struct</span> {
	<span style="color:#a6e22e">X</span>, <span style="color:#a6e22e">Y</span> <span style="color:#66d9ef">float64</span>
}

<span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">v</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">Vertex</span>) <span style="color:#a6e22e">Scale</span>(<span style="color:#a6e22e">f</span> <span style="color:#66d9ef">float64</span>) {
	<span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">X</span> = <span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">X</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">f</span>
	<span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Y</span> = <span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Y</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">f</span>
}

<span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">v</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">Vertex</span>) <span style="color:#a6e22e">Abs</span>() <span style="color:#66d9ef">float64</span> {
	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">math</span>.<span style="color:#a6e22e">Sqrt</span>(<span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">X</span><span style="color:#f92672">*</span><span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">X</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Y</span><span style="color:#f92672">*</span><span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Y</span>)
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">v</span> <span style="color:#f92672">:=</span> <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">Vertex</span>{<span style="color:#ae81ff">3</span>, <span style="color:#ae81ff">4</span>}
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;Before scaling: %+v, Abs: %v\n&#34;</span>, <span style="color:#a6e22e">v</span>, <span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Abs</span>())
	<span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Scale</span>(<span style="color:#ae81ff">5</span>)
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;After scaling: %+v, Abs: %v\n&#34;</span>, <span style="color:#a6e22e">v</span>, <span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Abs</span>())
}
</code></pre></div><h2 id="接口">接口</h2>
<p><strong>接口类型</strong> 是由一组方法签名定义的集合。</p>
<p>接口类型的变量可以保存任何实现了这些方法的值。</p>
<p><strong>注意:</strong> 示例代码的 22 行存在一个错误。由于 <code>Abs</code> 方法只为 <code>*Vertex</code> (指针类型)定义，因此 <code>Vertex</code>(值类型)并未实现 <code>Abser</code>。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;fmt&#34;</span>
	<span style="color:#e6db74">&#34;math&#34;</span>
)

<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Abser</span> <span style="color:#66d9ef">interface</span> {
	<span style="color:#a6e22e">Abs</span>() <span style="color:#66d9ef">float64</span>
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">a</span> <span style="color:#a6e22e">Abser</span>
	<span style="color:#a6e22e">f</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">MyFloat</span>(<span style="color:#f92672">-</span><span style="color:#a6e22e">math</span>.<span style="color:#a6e22e">Sqrt2</span>)
	<span style="color:#a6e22e">v</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">Vertex</span>{<span style="color:#ae81ff">3</span>, <span style="color:#ae81ff">4</span>}

	<span style="color:#a6e22e">a</span> = <span style="color:#a6e22e">f</span>  <span style="color:#75715e">// a MyFloat 实现了 Abser
</span><span style="color:#75715e"></span>	<span style="color:#a6e22e">a</span> = <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">v</span> <span style="color:#75715e">// a *Vertex 实现了 Abser
</span><span style="color:#75715e"></span>
	<span style="color:#75715e">// 下面一行，v 是一个 Vertex(而不是 *Vertex)
</span><span style="color:#75715e"></span>	<span style="color:#75715e">// 所以没有实现 Abser。
</span><span style="color:#75715e"></span>	<span style="color:#a6e22e">a</span> = <span style="color:#a6e22e">v</span>

	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">a</span>.<span style="color:#a6e22e">Abs</span>())
}

<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">MyFloat</span> <span style="color:#66d9ef">float64</span>

<span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">f</span> <span style="color:#a6e22e">MyFloat</span>) <span style="color:#a6e22e">Abs</span>() <span style="color:#66d9ef">float64</span> {
	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">f</span> &lt; <span style="color:#ae81ff">0</span> {
		<span style="color:#66d9ef">return</span> float64(<span style="color:#f92672">-</span><span style="color:#a6e22e">f</span>)
	}
	<span style="color:#66d9ef">return</span> float64(<span style="color:#a6e22e">f</span>)
}

<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Vertex</span> <span style="color:#66d9ef">struct</span> {
	<span style="color:#a6e22e">X</span>, <span style="color:#a6e22e">Y</span> <span style="color:#66d9ef">float64</span>
}

<span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">v</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">Vertex</span>) <span style="color:#a6e22e">Abs</span>() <span style="color:#66d9ef">float64</span> {
	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">math</span>.<span style="color:#a6e22e">Sqrt</span>(<span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">X</span><span style="color:#f92672">*</span><span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">X</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Y</span><span style="color:#f92672">*</span><span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Y</span>)
}
</code></pre></div><h2 id="映射的文法-1">映射的文法</h2>
<p>映射的文法与结构体相似，不过必须有键名。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Vertex</span> <span style="color:#66d9ef">struct</span> {
	<span style="color:#a6e22e">Lat</span>, <span style="color:#a6e22e">Long</span> <span style="color:#66d9ef">float64</span>
}

<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">m</span> = <span style="color:#66d9ef">map</span>[<span style="color:#66d9ef">string</span>]<span style="color:#a6e22e">Vertex</span>{
	<span style="color:#e6db74">&#34;Bell Labs&#34;</span>: <span style="color:#a6e22e">Vertex</span>{
		<span style="color:#ae81ff">40.68433</span>, <span style="color:#f92672">-</span><span style="color:#ae81ff">74.39967</span>,
	},
	<span style="color:#e6db74">&#34;Google&#34;</span>: <span style="color:#a6e22e">Vertex</span>{
		<span style="color:#ae81ff">37.42202</span>, <span style="color:#f92672">-</span><span style="color:#ae81ff">122.08408</span>,
	},
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">m</span>)
}

</code></pre></div><h2 id="接口与隐式实现">接口与隐式实现</h2>
<p>类型通过实现一个接口的所有方法来实现该接口。既然无需专门显式声明，也就没有“implements”关键字。</p>
<p>隐式接口从接口的实现中解耦了定义，这样接口的实现可以出现在任何包中，无需提前准备。</p>
<p>因此，也就无需在每一个实现上增加新的接口名称，这样同时也鼓励了明确的接口定义。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">I</span> <span style="color:#66d9ef">interface</span> {
	<span style="color:#a6e22e">M</span>()
}

<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">T</span> <span style="color:#66d9ef">struct</span> {
	<span style="color:#a6e22e">S</span> <span style="color:#66d9ef">string</span>
}

<span style="color:#75715e">// 此方法表示类型 T 实现了接口 I，但我们无需显式声明此事。
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">t</span> <span style="color:#a6e22e">T</span>) <span style="color:#a6e22e">M</span>() {
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">S</span>)
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">i</span> <span style="color:#a6e22e">I</span> = <span style="color:#a6e22e">T</span>{<span style="color:#e6db74">&#34;hello&#34;</span>}
	<span style="color:#a6e22e">i</span>.<span style="color:#a6e22e">M</span>()
}

</code></pre></div><h2 id="接口值">接口值</h2>
<p>接口也是值。它们可以像其它值一样传递。</p>
<p>接口值可以用作函数的参数或返回值。</p>
<p>在内部，接口值可以看做包含值和具体类型的元组：</p>
<pre><code>(value, type)
</code></pre><p>接口值保存了一个具体底层类型的具体值。</p>
<p>接口值调用方法时会执行其底层类型的同名方法。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;fmt&#34;</span>
	<span style="color:#e6db74">&#34;math&#34;</span>
)

<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">I</span> <span style="color:#66d9ef">interface</span> {
	<span style="color:#a6e22e">M</span>()
}

<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">T</span> <span style="color:#66d9ef">struct</span> {
	<span style="color:#a6e22e">S</span> <span style="color:#66d9ef">string</span>
}

<span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">T</span>) <span style="color:#a6e22e">M</span>() {
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">S</span>)
}

<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">F</span> <span style="color:#66d9ef">float64</span>

<span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">f</span> <span style="color:#a6e22e">F</span>) <span style="color:#a6e22e">M</span>() {
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">f</span>)
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">i</span> <span style="color:#a6e22e">I</span>

	<span style="color:#a6e22e">i</span> = <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">T</span>{<span style="color:#e6db74">&#34;Hello&#34;</span>}
	<span style="color:#a6e22e">describe</span>(<span style="color:#a6e22e">i</span>)
	<span style="color:#a6e22e">i</span>.<span style="color:#a6e22e">M</span>()

	<span style="color:#a6e22e">i</span> = <span style="color:#a6e22e">F</span>(<span style="color:#a6e22e">math</span>.<span style="color:#a6e22e">Pi</span>)
	<span style="color:#a6e22e">describe</span>(<span style="color:#a6e22e">i</span>)
	<span style="color:#a6e22e">i</span>.<span style="color:#a6e22e">M</span>()
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">describe</span>(<span style="color:#a6e22e">i</span> <span style="color:#a6e22e">I</span>) {
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;(%v, %T)\n&#34;</span>, <span style="color:#a6e22e">i</span>, <span style="color:#a6e22e">i</span>)
}

</code></pre></div><h2 id="底层值为-nil-的接口值">底层值为 nil 的接口值</h2>
<p>即便接口内的具体值为 nil，方法仍然会被 nil 接收者调用。</p>
<p>在一些语言中，这会触发一个空指针异常，但在 Go 中通常会写一些方法来优雅地处理它(如本例中的 <code>M</code> 方法)。</p>
<p><strong>注意:</strong> 保存了 nil 具体值的接口其自身并不为 nil。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">I</span> <span style="color:#66d9ef">interface</span> {
	<span style="color:#a6e22e">M</span>()
}

<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">T</span> <span style="color:#66d9ef">struct</span> {
	<span style="color:#a6e22e">S</span> <span style="color:#66d9ef">string</span>
}

<span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">T</span>) <span style="color:#a6e22e">M</span>() {
	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">t</span> <span style="color:#f92672">==</span> <span style="color:#66d9ef">nil</span> {
		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;&lt;nil&gt;&#34;</span>)
		<span style="color:#66d9ef">return</span>
	}
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">S</span>)
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">i</span> <span style="color:#a6e22e">I</span>

	<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">T</span>
	<span style="color:#a6e22e">i</span> = <span style="color:#a6e22e">t</span>
	<span style="color:#a6e22e">describe</span>(<span style="color:#a6e22e">i</span>)
	<span style="color:#a6e22e">i</span>.<span style="color:#a6e22e">M</span>()

	<span style="color:#a6e22e">i</span> = <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">T</span>{<span style="color:#e6db74">&#34;hello&#34;</span>}
	<span style="color:#a6e22e">describe</span>(<span style="color:#a6e22e">i</span>)
	<span style="color:#a6e22e">i</span>.<span style="color:#a6e22e">M</span>()
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">describe</span>(<span style="color:#a6e22e">i</span> <span style="color:#a6e22e">I</span>) {
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;(%v, %T)\n&#34;</span>, <span style="color:#a6e22e">i</span>, <span style="color:#a6e22e">i</span>)
}

</code></pre></div><h2 id="nil-接口值">nil 接口值</h2>
<p>nil 接口值既不保存值也不保存具体类型。</p>
<p>为 nil 接口调用方法会产生运行时错误，因为接口的元组内并未包含能够指明该调用哪个 <strong>具体</strong> 方法的类型。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">I</span> <span style="color:#66d9ef">interface</span> {
	<span style="color:#a6e22e">M</span>()
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">i</span> <span style="color:#a6e22e">I</span>
	<span style="color:#a6e22e">describe</span>(<span style="color:#a6e22e">i</span>)
	<span style="color:#a6e22e">i</span>.<span style="color:#a6e22e">M</span>()
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">describe</span>(<span style="color:#a6e22e">i</span> <span style="color:#a6e22e">I</span>) {
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;(%v, %T)\n&#34;</span>, <span style="color:#a6e22e">i</span>, <span style="color:#a6e22e">i</span>)
}

</code></pre></div><h2 id="空接口">空接口</h2>
<p>指定了零个方法的接口值被称为 <em>空接口：</em></p>
<pre><code>interface{}
</code></pre><p>空接口可保存任何类型的值。(因为每个类型都至少实现了零个方法。)</p>
<p>空接口被用来处理未知类型的值。例如，<code>fmt.Print</code> 可接受类型为 <code>interface{}</code> 的任意数量的参数。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">i</span> <span style="color:#66d9ef">interface</span>{}
	<span style="color:#a6e22e">describe</span>(<span style="color:#a6e22e">i</span>)

	<span style="color:#a6e22e">i</span> = <span style="color:#ae81ff">42</span>
	<span style="color:#a6e22e">describe</span>(<span style="color:#a6e22e">i</span>)

	<span style="color:#a6e22e">i</span> = <span style="color:#e6db74">&#34;hello&#34;</span>
	<span style="color:#a6e22e">describe</span>(<span style="color:#a6e22e">i</span>)
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">describe</span>(<span style="color:#a6e22e">i</span> <span style="color:#66d9ef">interface</span>{}) {
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;(%v, %T)\n&#34;</span>, <span style="color:#a6e22e">i</span>, <span style="color:#a6e22e">i</span>)
}

</code></pre></div><h2 id="类型断言">类型断言</h2>
<p><strong>类型断言</strong> 提供了访问接口值底层具体值的方式。</p>
<pre><code>t := i.(T)
</code></pre><p>该语句断言接口值 <code>i</code> 保存了具体类型 <code>T</code>，并将其底层类型为 <code>T</code> 的值赋予变量 <code>t</code>。</p>
<p>若 <code>i</code> 并未保存 <code>T</code> 类型的值，该语句就会触发一个恐慌。</p>
<p>为了 <strong>判断</strong> 一个接口值是否保存了一个特定的类型，类型断言可返回两个值：其底层值以及一个报告断言是否成功的布尔值。</p>
<pre><code>t, ok := i.(T)
</code></pre><p>若 <code>i</code> 保存了一个 <code>T</code>，那么 <code>t</code> 将会是其底层值，而 <code>ok</code> 为 <code>true</code>。</p>
<p>否则，<code>ok</code> 将为 <code>false</code> 而 <code>t</code> 将为 <code>T</code> 类型的零值，程序并不会产生恐慌。</p>
<p>请注意这种语法和读取一个映射时的相同之处。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">i</span> <span style="color:#66d9ef">interface</span>{} = <span style="color:#e6db74">&#34;hello&#34;</span>

	<span style="color:#a6e22e">s</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">i</span>.(<span style="color:#66d9ef">string</span>)
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">s</span>)

	<span style="color:#a6e22e">s</span>, <span style="color:#a6e22e">ok</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">i</span>.(<span style="color:#66d9ef">string</span>)
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">s</span>, <span style="color:#a6e22e">ok</span>)

	<span style="color:#a6e22e">f</span>, <span style="color:#a6e22e">ok</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">i</span>.(<span style="color:#66d9ef">float64</span>)
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">f</span>, <span style="color:#a6e22e">ok</span>)

	<span style="color:#a6e22e">f</span> = <span style="color:#a6e22e">i</span>.(<span style="color:#66d9ef">float64</span>) <span style="color:#75715e">// 报错(panic)
</span><span style="color:#75715e"></span>	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">f</span>)
}

</code></pre></div><h2 id="类型选择">类型选择</h2>
<p><strong>类型选择</strong> 是一种按顺序从几个类型断言中选择分支的结构。</p>
<p>类型选择与一般的 switch 语句相似，不过类型选择中的 case 为类型(而非值)， 它们针对给定接口值所存储的值的类型进行比较。</p>
<pre><code>switch v := i.(type) {
case T:
    // v 的类型为 T
case S:
    // v 的类型为 S
default:
    // 没有匹配，v 与 i 的类型相同
}
</code></pre><p>类型选择中的声明与类型断言 <code>i.(T)</code> 的语法相同，只是具体类型 <code>T</code> 被替换成了关键字 <code>type</code>。</p>
<p>此选择语句判断接口值 <code>i</code> 保存的值类型是 <code>T</code> 还是 <code>S</code>。在 <code>T</code> 或 <code>S</code> 的情况下，变量 <code>v</code> 会分别按 <code>T</code> 或 <code>S</code> 类型保存 <code>i</code> 拥有的值。在默认(即没有匹配)的情况下，变量 <code>v</code> 与 <code>i</code> 的接口类型和值相同。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">do</span>(<span style="color:#a6e22e">i</span> <span style="color:#66d9ef">interface</span>{}) {
	<span style="color:#66d9ef">switch</span> <span style="color:#a6e22e">v</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">i</span>.(<span style="color:#66d9ef">type</span>) {
	<span style="color:#66d9ef">case</span> <span style="color:#66d9ef">int</span>:
		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;Twice %v is %v\n&#34;</span>, <span style="color:#a6e22e">v</span>, <span style="color:#a6e22e">v</span><span style="color:#f92672">*</span><span style="color:#ae81ff">2</span>)
	<span style="color:#66d9ef">case</span> <span style="color:#66d9ef">string</span>:
		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;%q is %v bytes long\n&#34;</span>, <span style="color:#a6e22e">v</span>, len(<span style="color:#a6e22e">v</span>))
	<span style="color:#66d9ef">default</span>:
		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;I don&#39;t know about type %T!\n&#34;</span>, <span style="color:#a6e22e">v</span>)
	}
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">do</span>(<span style="color:#ae81ff">21</span>)
	<span style="color:#a6e22e">do</span>(<span style="color:#e6db74">&#34;hello&#34;</span>)
	<span style="color:#a6e22e">do</span>(<span style="color:#66d9ef">true</span>)
}

</code></pre></div><h2 id="stringer">Stringer</h2>
<p><a href="https://go-zh.org/pkg/fmt/"><code>fmt</code></a> 包中定义的 <a href="https://go-zh.org/pkg/fmt/#Stringer"><code>Stringer</code></a> 是最普遍的接口之一。</p>
<pre><code>type Stringer interface {
    String() string
}
</code></pre><p><code>Stringer</code> 是一个可以用字符串描述自己的类型。<code>fmt</code> 包(还有很多包)都通过此接口来打印值。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Person</span> <span style="color:#66d9ef">struct</span> {
	<span style="color:#a6e22e">Name</span> <span style="color:#66d9ef">string</span>
	<span style="color:#a6e22e">Age</span>  <span style="color:#66d9ef">int</span>
}

<span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">p</span> <span style="color:#a6e22e">Person</span>) <span style="color:#a6e22e">String</span>() <span style="color:#66d9ef">string</span> {
	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Sprintf</span>(<span style="color:#e6db74">&#34;%v (%v years)&#34;</span>, <span style="color:#a6e22e">p</span>.<span style="color:#a6e22e">Name</span>, <span style="color:#a6e22e">p</span>.<span style="color:#a6e22e">Age</span>)
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">a</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">Person</span>{<span style="color:#e6db74">&#34;Arthur Dent&#34;</span>, <span style="color:#ae81ff">42</span>}
	<span style="color:#a6e22e">z</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">Person</span>{<span style="color:#e6db74">&#34;Zaphod Beeblebrox&#34;</span>, <span style="color:#ae81ff">9001</span>}
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">a</span>, <span style="color:#a6e22e">z</span>)
}

</code></pre></div><h2 id="练习stringer">练习：Stringer</h2>
<p>通过让 <code>IPAddr</code> 类型实现 <code>fmt.Stringer</code> 来打印点号分隔的地址。</p>
<p>例如，<code>IPAddr{1, 2, 3, 4}</code> 应当打印为 <code>&quot;1.2.3.4&quot;</code>。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">IPAddr</span> [<span style="color:#ae81ff">4</span>]<span style="color:#66d9ef">byte</span>

<span style="color:#75715e">// TODO: 给 IPAddr 添加一个 &#34;String() string&#34; 方法
</span><span style="color:#75715e"></span>
<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">hosts</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">map</span>[<span style="color:#66d9ef">string</span>]<span style="color:#a6e22e">IPAddr</span>{
		<span style="color:#e6db74">&#34;loopback&#34;</span>:  {<span style="color:#ae81ff">127</span>, <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">1</span>},
		<span style="color:#e6db74">&#34;googleDNS&#34;</span>: {<span style="color:#ae81ff">8</span>, <span style="color:#ae81ff">8</span>, <span style="color:#ae81ff">8</span>, <span style="color:#ae81ff">8</span>},
	}
	<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">name</span>, <span style="color:#a6e22e">ip</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">hosts</span> {
		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;%v: %v\n&#34;</span>, <span style="color:#a6e22e">name</span>, <span style="color:#a6e22e">ip</span>)
	}
}

</code></pre></div><h2 id="错误">错误</h2>
<p>Go 程序使用 <code>error</code> 值来表示错误状态。</p>
<p>与 <code>fmt.Stringer</code> 类似，<code>error</code> 类型是一个内建接口：</p>
<pre><code>type error interface {
    Error() string
}
</code></pre><p>(与 <code>fmt.Stringer</code> 类似，<code>fmt</code> 包在打印值时也会满足 <code>error</code>。)</p>
<p>通常函数会返回一个 <code>error</code> 值，调用的它的代码应当判断这个错误是否等于 <code>nil</code> 来进行错误处理。</p>
<pre><code>i, err := strconv.Atoi(&quot;42&quot;)
if err != nil {
    fmt.Printf(&quot;couldn't convert number: %v\n&quot;, err)
    return
}
fmt.Println(&quot;Converted integer:&quot;, i)
</code></pre><p><code>error</code> 为 nil 时表示成功；非 nil 的 <code>error</code> 表示失败。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;fmt&#34;</span>
	<span style="color:#e6db74">&#34;time&#34;</span>
)

<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">MyError</span> <span style="color:#66d9ef">struct</span> {
	<span style="color:#a6e22e">When</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Time</span>
	<span style="color:#a6e22e">What</span> <span style="color:#66d9ef">string</span>
}

<span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">e</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">MyError</span>) <span style="color:#a6e22e">Error</span>() <span style="color:#66d9ef">string</span> {
	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Sprintf</span>(<span style="color:#e6db74">&#34;at %v, %s&#34;</span>,
		<span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">When</span>, <span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">What</span>)
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">run</span>() <span style="color:#66d9ef">error</span> {
	<span style="color:#66d9ef">return</span> <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">MyError</span>{
		<span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Now</span>(),
		<span style="color:#e6db74">&#34;it didn&#39;t work&#34;</span>,
	}
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">run</span>(); <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">err</span>)
	}
}
</code></pre></div><h2 id="练习错误">练习：错误</h2>
<p>从中复制 <code>Sqrt</code> 函数，修改它使其返回 <code>error</code> 值。</p>
<p><code>Sqrt</code> 接受到一个负数时，应当返回一个非 nil 的错误值。复数同样也不被支持。</p>
<p>创建一个新的类型</p>
<pre><code>type ErrNegativeSqrt float64
</code></pre><p>并为其实现</p>
<pre><code>func (e ErrNegativeSqrt) Error() string
</code></pre><p>方法使其拥有 <code>error</code> 值，通过 <code>ErrNegativeSqrt(-2).Error()</code> 调用该方法应返回 <code>&quot;cannot Sqrt negative number: -2&quot;</code>。</p>
<p><strong>注意:</strong> 在 <code>Error</code> 方法内调用 <code>fmt.Sprint(e)</code> 会让程序陷入死循环。可以通过先转换 <code>e</code> 来避免这个问题：<code>fmt.Sprint(float64(e))</code>。这是为什么呢？</p>
<p>修改 <code>Sqrt</code> 函数，使其接受一个负数时，返回 <code>ErrNegativeSqrt</code></p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;fmt&#34;</span>
)

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">Sqrt</span>(<span style="color:#a6e22e">x</span> <span style="color:#66d9ef">float64</span>) (<span style="color:#66d9ef">float64</span>, <span style="color:#66d9ef">error</span>) {
	<span style="color:#66d9ef">return</span> <span style="color:#ae81ff">0</span>, <span style="color:#66d9ef">nil</span>
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">Sqrt</span>(<span style="color:#ae81ff">2</span>))
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">Sqrt</span>(<span style="color:#f92672">-</span><span style="color:#ae81ff">2</span>))
}

</code></pre></div><h2 id="reader">Reader</h2>
<p><code>io</code> 包指定了 <code>io.Reader</code> 接口，它表示从数据流的末尾进行读取。</p>
<p>Go 标准库包含了该接口的<a href="https://go-zh.org/search?q=Read#Global">许多实现</a>，包括文件、网络连接、压缩和加密等等。</p>
<p><code>io.Reader</code> 接口有一个 <code>Read</code> 方法：</p>
<pre><code>func (T) Read(b []byte) (n int, err error)
</code></pre><p><code>Read</code> 用数据填充给定的字节切片并返回填充的字节数和错误值。在遇到数据流的结尾时，它会返回一个 <code>io.EOF</code> 错误。</p>
<p>示例代码创建了一个 <a href="https://go-zh.org/pkg/strings/#Reader"><code>strings.Reader</code></a> 并以每次 8 字节的速度读取它的输出。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;fmt&#34;</span>
	<span style="color:#e6db74">&#34;io&#34;</span>
	<span style="color:#e6db74">&#34;strings&#34;</span>
)

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">r</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">NewReader</span>(<span style="color:#e6db74">&#34;Hello, Reader!&#34;</span>)

	<span style="color:#a6e22e">b</span> <span style="color:#f92672">:=</span> make([]<span style="color:#66d9ef">byte</span>, <span style="color:#ae81ff">8</span>)
	<span style="color:#66d9ef">for</span> {
		<span style="color:#a6e22e">n</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">r</span>.<span style="color:#a6e22e">Read</span>(<span style="color:#a6e22e">b</span>)
		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;n = %v err = %v b = %v\n&#34;</span>, <span style="color:#a6e22e">n</span>, <span style="color:#a6e22e">err</span>, <span style="color:#a6e22e">b</span>)
		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;b[:n] = %q\n&#34;</span>, <span style="color:#a6e22e">b</span>[:<span style="color:#a6e22e">n</span>])
		<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">==</span> <span style="color:#a6e22e">io</span>.<span style="color:#a6e22e">EOF</span> {
			<span style="color:#66d9ef">break</span>
		}
	}
}

</code></pre></div><h2 id="练习reader">练习：Reader</h2>
<p>实现一个 <code>Reader</code> 类型，它产生一个 ASCII 字符 <code>'A'</code> 的无限流。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;golang.org/x/tour/reader&#34;</span>

<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">MyReader</span> <span style="color:#66d9ef">struct</span>{}

<span style="color:#75715e">// TODO: 给 MyReader 添加一个 Read([]byte) (int, error) 方法
</span><span style="color:#75715e"></span>
<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">reader</span>.<span style="color:#a6e22e">Validate</span>(<span style="color:#a6e22e">MyReader</span>{})
}

</code></pre></div><h2 id="练习rot13reader">练习：rot13Reader</h2>
<p>有种常见的模式是一个 <a href="https://go-zh.org/pkg/io/#Reader"><code>io.Reader</code></a> 包装另一个 <code>io.Reader</code>，然后通过某种方式修改其数据流。</p>
<p>例如，<a href="https://go-zh.org/pkg/compress/gzip/#NewReader"><code>gzip.NewReader</code></a> 函数接受一个 <code>io.Reader</code>(已压缩的数据流)并返回一个同样实现了 <code>io.Reader</code> 的 <code>*gzip.Reader</code>(解压后的数据流)。</p>
<p>编写一个实现了 <code>io.Reader</code> 并从另一个 <code>io.Reader</code> 中读取数据的 <code>rot13Reader</code>，通过应用 <a href="http://en.wikipedia.org/wiki/ROT13">rot13</a> 代换密码对数据流进行修改。</p>
<p><code>rot13Reader</code> 类型已经提供。实现 <code>Read</code> 方法以满足 <code>io.Reader</code>。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;io&#34;</span>
	<span style="color:#e6db74">&#34;os&#34;</span>
	<span style="color:#e6db74">&#34;strings&#34;</span>
)

<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">rot13Reader</span> <span style="color:#66d9ef">struct</span> {
	<span style="color:#a6e22e">r</span> <span style="color:#a6e22e">io</span>.<span style="color:#a6e22e">Reader</span>
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">s</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">NewReader</span>(<span style="color:#e6db74">&#34;Lbh penpxrq gur pbqr!&#34;</span>)
	<span style="color:#a6e22e">r</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">rot13Reader</span>{<span style="color:#a6e22e">s</span>}
	<span style="color:#a6e22e">io</span>.<span style="color:#a6e22e">Copy</span>(<span style="color:#a6e22e">os</span>.<span style="color:#a6e22e">Stdout</span>, <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">r</span>)
}

</code></pre></div><h2 id="图像">图像</h2>
<p><a href="https://go-zh.org/pkg/image/#Image"><code>image</code></a> 包定义了 <code>Image</code> 接口：</p>
<pre><code>package image

type Image interface {
    ColorModel() color.Model
    Bounds() Rectangle
    At(x, y int) color.Color
}
</code></pre><p><strong>注意:</strong> <code>Bounds</code> 方法的返回值 <code>Rectangle</code> 实际上是一个 <a href="https://go-zh.org/pkg/image/#Rectangle"><code>image.Rectangle</code></a>，它在 <code>image</code> 包中声明。</p>
<p>(请参阅<a href="https://go-zh.org/pkg/image/#Image">文档</a>了解全部信息。)</p>
<p><code>color.Color</code> 和 <code>color.Model</code> 类型也是接口，但是通常因为直接使用预定义的实现 <code>image.RGBA</code> 和 <code>image.RGBAModel</code> 而被忽视了。这些接口和类型由 <a href="https://go-zh.org/pkg/image/color/"><code>image/color</code></a> 包定义。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;fmt&#34;</span>
	<span style="color:#e6db74">&#34;image&#34;</span>
)

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">m</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">image</span>.<span style="color:#a6e22e">NewRGBA</span>(<span style="color:#a6e22e">image</span>.<span style="color:#a6e22e">Rect</span>(<span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">100</span>, <span style="color:#ae81ff">100</span>))
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">m</span>.<span style="color:#a6e22e">Bounds</span>())
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">m</span>.<span style="color:#a6e22e">At</span>(<span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>).<span style="color:#a6e22e">RGBA</span>())
}

</code></pre></div><h2 id="练习图像">练习：图像</h2>
<p>还记得之前编写的<a href="https://tour.go-zh.org/moretypes/18">图片生成器</a> 吗？我们再来编写另外一个，不过这次它将会返回一个 <code>image.Image</code> 的实现而非一个数据切片。</p>
<p>定义你自己的 <code>Image</code> 类型，实现<a href="https://go-zh.org/pkg/image/#Image">必要的方法</a>并调用 <code>pic.ShowImage</code>。</p>
<p><code>Bounds</code> 应当返回一个 <code>image.Rectangle</code> ，例如 <code>image.Rect(0, 0, w, h)</code>。</p>
<p><code>ColorModel</code> 应当返回 <code>color.RGBAModel</code>。</p>
<p><code>At</code> 应当返回一个颜色。上一个图片生成器的值 <code>v</code> 对应于此次的 <code>color.RGBA{v, v, 255, 255}</code>。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;golang.org/x/tour/pic&#34;</span>

<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Image</span> <span style="color:#66d9ef">struct</span>{}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">m</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">Image</span>{}
	<span style="color:#a6e22e">pic</span>.<span style="color:#a6e22e">ShowImage</span>(<span style="color:#a6e22e">m</span>)
}

</code></pre></div><h2 id="go-程">Go 程</h2>
<p>Go 程(goroutine)是由 Go 运行时管理的轻量级线程。</p>
<pre><code>go f(x, y, z)
</code></pre><p>会启动一个新的 Go 程并执行</p>
<pre><code>f(x, y, z)
</code></pre><p><code>f</code>, <code>x</code>, <code>y</code> 和 <code>z</code> 的求值发生在当前的 Go 程中，而 <code>f</code> 的执行发生在新的 Go 程中。</p>
<p>Go 程在相同的地址空间中运行，因此在访问共享的内存时必须进行同步。<a href="https://go-zh.org/pkg/sync/"><code>sync</code></a> 包提供了这种能力，不过在 Go 中并不经常用到，因为还有其它的办法(见下一页)。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;fmt&#34;</span>
	<span style="color:#e6db74">&#34;time&#34;</span>
)

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">say</span>(<span style="color:#a6e22e">s</span> <span style="color:#66d9ef">string</span>) {
	<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">i</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">0</span>; <span style="color:#a6e22e">i</span> &lt; <span style="color:#ae81ff">5</span>; <span style="color:#a6e22e">i</span><span style="color:#f92672">++</span> {
		<span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Sleep</span>(<span style="color:#ae81ff">100</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Millisecond</span>)
		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">s</span>)
	}
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#66d9ef">go</span> <span style="color:#a6e22e">say</span>(<span style="color:#e6db74">&#34;world&#34;</span>)
	<span style="color:#a6e22e">say</span>(<span style="color:#e6db74">&#34;hello&#34;</span>)
}

</code></pre></div><h2 id="信道">信道</h2>
<p>信道是带有类型的管道，你可以通过它用信道操作符 <code>&lt;-</code> 来发送或者接收值。</p>
<pre><code>ch &lt;- v    // 将 v 发送至信道 ch。
v := &lt;-ch  // 从 ch 接收值并赋予 v。
</code></pre><p>(“箭头”就是数据流的方向。)</p>
<p>和映射与切片一样，信道在使用前必须创建：</p>
<pre><code>ch := make(chan int)
</code></pre><p>默认情况下，发送和接收操作在另一端准备好之前都会阻塞。这使得 Go 程可以在没有显式的锁或竞态变量的情况下进行同步。</p>
<p>以下示例对切片中的数进行求和，将任务分配给两个 Go 程。一旦两个 Go 程完成了它们的计算，它就能算出最终的结果。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">sum</span>(<span style="color:#a6e22e">s</span> []<span style="color:#66d9ef">int</span>, <span style="color:#a6e22e">c</span> <span style="color:#66d9ef">chan</span> <span style="color:#66d9ef">int</span>) {
	<span style="color:#a6e22e">sum</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">0</span>
	<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">v</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">s</span> {
		<span style="color:#a6e22e">sum</span> <span style="color:#f92672">+=</span> <span style="color:#a6e22e">v</span>
	}
	<span style="color:#a6e22e">c</span> <span style="color:#f92672">&lt;-</span> <span style="color:#a6e22e">sum</span> <span style="color:#75715e">// 将和送入 c
</span><span style="color:#75715e"></span>}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">s</span> <span style="color:#f92672">:=</span> []<span style="color:#66d9ef">int</span>{<span style="color:#ae81ff">7</span>, <span style="color:#ae81ff">2</span>, <span style="color:#ae81ff">8</span>, <span style="color:#f92672">-</span><span style="color:#ae81ff">9</span>, <span style="color:#ae81ff">4</span>, <span style="color:#ae81ff">0</span>}

	<span style="color:#a6e22e">c</span> <span style="color:#f92672">:=</span> make(<span style="color:#66d9ef">chan</span> <span style="color:#66d9ef">int</span>)
	<span style="color:#66d9ef">go</span> <span style="color:#a6e22e">sum</span>(<span style="color:#a6e22e">s</span>[:len(<span style="color:#a6e22e">s</span>)<span style="color:#f92672">/</span><span style="color:#ae81ff">2</span>], <span style="color:#a6e22e">c</span>)
	<span style="color:#66d9ef">go</span> <span style="color:#a6e22e">sum</span>(<span style="color:#a6e22e">s</span>[len(<span style="color:#a6e22e">s</span>)<span style="color:#f92672">/</span><span style="color:#ae81ff">2</span>:], <span style="color:#a6e22e">c</span>)
	<span style="color:#a6e22e">x</span>, <span style="color:#a6e22e">y</span> <span style="color:#f92672">:=</span> <span style="color:#f92672">&lt;-</span><span style="color:#a6e22e">c</span>, <span style="color:#f92672">&lt;-</span><span style="color:#a6e22e">c</span> <span style="color:#75715e">// 从 c 中接收
</span><span style="color:#75715e"></span>
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">x</span>, <span style="color:#a6e22e">y</span>, <span style="color:#a6e22e">x</span><span style="color:#f92672">+</span><span style="color:#a6e22e">y</span>)
}

</code></pre></div><h2 id="带缓冲的信道">带缓冲的信道</h2>
<p>信道可以是 <em>带缓冲的</em>。将缓冲长度作为第二个参数提供给 <code>make</code> 来初始化一个带缓冲的信道：</p>
<pre><code>ch := make(chan int, 100)
</code></pre><p>仅当信道的缓冲区填满后，向其发送数据时才会阻塞。当缓冲区为空时，接受方会阻塞。</p>
<p>修改示例填满缓冲区，然后看看会发生什么。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">ch</span> <span style="color:#f92672">:=</span> make(<span style="color:#66d9ef">chan</span> <span style="color:#66d9ef">int</span>, <span style="color:#ae81ff">2</span>)
	<span style="color:#a6e22e">ch</span> <span style="color:#f92672">&lt;-</span> <span style="color:#ae81ff">1</span>
	<span style="color:#a6e22e">ch</span> <span style="color:#f92672">&lt;-</span> <span style="color:#ae81ff">2</span>
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#f92672">&lt;-</span><span style="color:#a6e22e">ch</span>)
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#f92672">&lt;-</span><span style="color:#a6e22e">ch</span>)
}

</code></pre></div><h2 id="range-和-close">range 和 close</h2>
<p>发送者可通过 <code>close</code> 关闭一个信道来表示没有需要发送的值了。接收者可以通过为接收表达式分配第二个参数来测试信道是否被关闭：若没有值可以接收且信道已被关闭，那么在执行完</p>
<pre><code>v, ok := &lt;-ch
</code></pre><p>之后 <code>ok</code> 会被设置为 <code>false</code>。</p>
<p>循环 <code>for i := range c</code> 会不断从信道接收值，直到它被关闭。</p>
<p><em>注意：</em> 只有发送者才能关闭信道，而接收者不能。向一个已经关闭的信道发送数据会引发程序恐慌(panic)。</p>
<p><em>还要注意：</em> 信道与文件不同，通常情况下无需关闭它们。只有在必须告诉接收者不再有需要发送的值时才有必要关闭，例如终止一个 <code>range</code> 循环。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;fmt&#34;</span>
)

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">fibonacci</span>(<span style="color:#a6e22e">n</span> <span style="color:#66d9ef">int</span>, <span style="color:#a6e22e">c</span> <span style="color:#66d9ef">chan</span> <span style="color:#66d9ef">int</span>) {
	<span style="color:#a6e22e">x</span>, <span style="color:#a6e22e">y</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">1</span>
	<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">i</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">0</span>; <span style="color:#a6e22e">i</span> &lt; <span style="color:#a6e22e">n</span>; <span style="color:#a6e22e">i</span><span style="color:#f92672">++</span> {
		<span style="color:#a6e22e">c</span> <span style="color:#f92672">&lt;-</span> <span style="color:#a6e22e">x</span>
		<span style="color:#a6e22e">x</span>, <span style="color:#a6e22e">y</span> = <span style="color:#a6e22e">y</span>, <span style="color:#a6e22e">x</span><span style="color:#f92672">+</span><span style="color:#a6e22e">y</span>
	}
	close(<span style="color:#a6e22e">c</span>)
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">c</span> <span style="color:#f92672">:=</span> make(<span style="color:#66d9ef">chan</span> <span style="color:#66d9ef">int</span>, <span style="color:#ae81ff">10</span>)
	<span style="color:#66d9ef">go</span> <span style="color:#a6e22e">fibonacci</span>(cap(<span style="color:#a6e22e">c</span>), <span style="color:#a6e22e">c</span>)
	<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">i</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">c</span> {
		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">i</span>)
	}
}

</code></pre></div><h2 id="select-语句">select 语句</h2>
<p><code>select</code> 语句使一个 Go 程可以等待多个通信操作。</p>
<p><code>select</code> 会阻塞到某个分支可以继续执行为止，这时就会执行该分支。当多个分支都准备好时会随机选择一个执行。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;fmt&#34;</span>

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">fibonacci</span>(<span style="color:#a6e22e">c</span>, <span style="color:#a6e22e">quit</span> <span style="color:#66d9ef">chan</span> <span style="color:#66d9ef">int</span>) {
	<span style="color:#a6e22e">x</span>, <span style="color:#a6e22e">y</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">1</span>
	<span style="color:#66d9ef">for</span> {
		<span style="color:#66d9ef">select</span> {
		<span style="color:#66d9ef">case</span> <span style="color:#a6e22e">c</span> <span style="color:#f92672">&lt;-</span> <span style="color:#a6e22e">x</span>:
			<span style="color:#a6e22e">x</span>, <span style="color:#a6e22e">y</span> = <span style="color:#a6e22e">y</span>, <span style="color:#a6e22e">x</span><span style="color:#f92672">+</span><span style="color:#a6e22e">y</span>
		<span style="color:#66d9ef">case</span> <span style="color:#f92672">&lt;-</span><span style="color:#a6e22e">quit</span>:
			<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;quit&#34;</span>)
			<span style="color:#66d9ef">return</span>
		}
	}
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">c</span> <span style="color:#f92672">:=</span> make(<span style="color:#66d9ef">chan</span> <span style="color:#66d9ef">int</span>)
	<span style="color:#a6e22e">quit</span> <span style="color:#f92672">:=</span> make(<span style="color:#66d9ef">chan</span> <span style="color:#66d9ef">int</span>)
	<span style="color:#66d9ef">go</span> <span style="color:#66d9ef">func</span>() {
		<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">i</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">0</span>; <span style="color:#a6e22e">i</span> &lt; <span style="color:#ae81ff">10</span>; <span style="color:#a6e22e">i</span><span style="color:#f92672">++</span> {
			<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#f92672">&lt;-</span><span style="color:#a6e22e">c</span>)
		}
		<span style="color:#a6e22e">quit</span> <span style="color:#f92672">&lt;-</span> <span style="color:#ae81ff">0</span>
	}()
	<span style="color:#a6e22e">fibonacci</span>(<span style="color:#a6e22e">c</span>, <span style="color:#a6e22e">quit</span>)
}
</code></pre></div><h2 id="默认选择">默认选择</h2>
<p>当 <code>select</code> 中的其它分支都没有准备好时，<code>default</code> 分支就会执行。</p>
<p>为了在尝试发送或者接收时不发生阻塞，可使用 <code>default</code> 分支：</p>
<pre><code>select {
case i := &lt;-c:
    // 使用 i
default:
    // 从 c 中接收会阻塞时执行
}
</code></pre><div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;fmt&#34;</span>
	<span style="color:#e6db74">&#34;time&#34;</span>
)

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">tick</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Tick</span>(<span style="color:#ae81ff">100</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Millisecond</span>)
	<span style="color:#a6e22e">boom</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">After</span>(<span style="color:#ae81ff">500</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Millisecond</span>)
	<span style="color:#66d9ef">for</span> {
		<span style="color:#66d9ef">select</span> {
		<span style="color:#66d9ef">case</span> <span style="color:#f92672">&lt;-</span><span style="color:#a6e22e">tick</span>:
			<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;tick.&#34;</span>)
		<span style="color:#66d9ef">case</span> <span style="color:#f92672">&lt;-</span><span style="color:#a6e22e">boom</span>:
			<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;BOOM!&#34;</span>)
			<span style="color:#66d9ef">return</span>
		<span style="color:#66d9ef">default</span>:
			<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;    .&#34;</span>)
			<span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Sleep</span>(<span style="color:#ae81ff">50</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Millisecond</span>)
		}
	}
}

</code></pre></div><h2 id="练习等价二叉查找树">练习：等价二叉查找树</h2>
<p>不同二叉树的叶节点上可以保存相同的值序列。例如，以下两个二叉树都保存了序列 <code>1，1，2，3，5，8，13</code>。</p>
<p>
        <a data-fancybox="gallery" href="https://luckly007.oss-cn-beijing.aliyuncs.com/image/tree.png">
            <img class="mx-auto" alt="img" src="https://luckly007.oss-cn-beijing.aliyuncs.com/image/tree.png" />
        </a>
    </p>
<p>在大多数语言中，检查两个二叉树是否保存了相同序列的函数都相当复杂。 我们将使用 Go 的并发和信道来编写一个简单的解法。</p>
<p>本例使用了 <code>tree</code> 包，它定义了类型：</p>
<pre><code>type Tree struct {
    Left  *Tree
    Value int
    Right *Tree
}
</code></pre><h2 id="练习等价二叉查找树-1">练习：等价二叉查找树</h2>
<p><strong>1.</strong> 实现 <code>Walk</code> 函数。</p>
<p><strong>2.</strong> 测试 <code>Walk</code> 函数。</p>
<p>函数 <code>tree.New(k)</code> 用于构造一个随机结构的已排序二叉查找树，它保存了值 <code>k</code>, <code>2k</code>, <code>3k</code>, &hellip;, <code>10k</code>。</p>
<p>创建一个新的信道 <code>ch</code> 并且对其进行步进：</p>
<pre><code>go Walk(tree.New(1), ch)
</code></pre><p>然后从信道中读取并打印 10 个值。应当是数字 <code>1, 2, 3, ..., 10</code>。</p>
<p><strong>3.</strong> 用 <code>Walk</code> 实现 <code>Same</code> 函数来检测 <code>t1</code> 和 <code>t2</code> 是否存储了相同的值。</p>
<p><strong>4.</strong> 测试 <code>Same</code> 函数。</p>
<p><code>Same(tree.New(1), tree.New(1))</code> 应当返回 <code>true</code>，而 <code>Same(tree.New(1), tree.New(2))</code> 应当返回 <code>false</code>。</p>
<p><code>Tree</code> 的文档可在<a href="https://godoc.org/golang.org/x/tour/tree#Tree">这里</a>找到。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;golang.org/x/tour/tree&#34;</span>

<span style="color:#75715e">// Walk 步进 tree t 将所有的值从 tree 发送到 channel ch。
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">Walk</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">tree</span>.<span style="color:#a6e22e">Tree</span>, <span style="color:#a6e22e">ch</span> <span style="color:#66d9ef">chan</span> <span style="color:#66d9ef">int</span>)

<span style="color:#75715e">// Same 检测树 t1 和 t2 是否含有相同的值。
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">Same</span>(<span style="color:#a6e22e">t1</span>, <span style="color:#a6e22e">t2</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">tree</span>.<span style="color:#a6e22e">Tree</span>) <span style="color:#66d9ef">bool</span>

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
}

</code></pre></div><h2 id="syncmutex">sync.Mutex</h2>
<p>我们已经看到信道非常适合在各个 Go 程间进行通信。</p>
<p>但是如果我们并不需要通信呢？比如说，若我们只是想保证每次只有一个 Go 程能够访问一个共享的变量，从而避免冲突？</p>
<p>这里涉及的概念叫做 <em>互斥(mutual</em>exclusion)* ，我们通常使用 *互斥锁(Mutex)* 这一数据结构来提供这种机制。</p>
<p>Go 标准库中提供了 <a href="https://go-zh.org/pkg/sync/#Mutex"><code>sync.Mutex</code></a> 互斥锁类型及其两个方法：</p>
<ul>
<li><code>Lock</code></li>
<li><code>Unlock</code></li>
</ul>
<p>我们可以通过在代码前调用 <code>Lock</code> 方法，在代码后调用 <code>Unlock</code> 方法来保证一段代码的互斥执行。参见 <code>Inc</code> 方法。</p>
<p>我们也可以用 <code>defer</code> 语句来保证互斥锁一定会被解锁。参见 <code>Value</code> 方法。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;fmt&#34;</span>
	<span style="color:#e6db74">&#34;sync&#34;</span>
	<span style="color:#e6db74">&#34;time&#34;</span>
)

<span style="color:#75715e">// SafeCounter 的并发使用是安全的。
</span><span style="color:#75715e"></span><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">SafeCounter</span> <span style="color:#66d9ef">struct</span> {
	<span style="color:#a6e22e">v</span>   <span style="color:#66d9ef">map</span>[<span style="color:#66d9ef">string</span>]<span style="color:#66d9ef">int</span>
	<span style="color:#a6e22e">mux</span> <span style="color:#a6e22e">sync</span>.<span style="color:#a6e22e">Mutex</span>
}

<span style="color:#75715e">// Inc 增加给定 key 的计数器的值。
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">c</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">SafeCounter</span>) <span style="color:#a6e22e">Inc</span>(<span style="color:#a6e22e">key</span> <span style="color:#66d9ef">string</span>) {
	<span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">mux</span>.<span style="color:#a6e22e">Lock</span>()
	<span style="color:#75715e">// Lock 之后同一时刻只有一个 goroutine 能访问 c.v
</span><span style="color:#75715e"></span>	<span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">v</span>[<span style="color:#a6e22e">key</span>]<span style="color:#f92672">++</span>
	<span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">mux</span>.<span style="color:#a6e22e">Unlock</span>()
}

<span style="color:#75715e">// Value 返回给定 key 的计数器的当前值。
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">c</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">SafeCounter</span>) <span style="color:#a6e22e">Value</span>(<span style="color:#a6e22e">key</span> <span style="color:#66d9ef">string</span>) <span style="color:#66d9ef">int</span> {
	<span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">mux</span>.<span style="color:#a6e22e">Lock</span>()
	<span style="color:#75715e">// Lock 之后同一时刻只有一个 goroutine 能访问 c.v
</span><span style="color:#75715e"></span>	<span style="color:#66d9ef">defer</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">mux</span>.<span style="color:#a6e22e">Unlock</span>()
	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">v</span>[<span style="color:#a6e22e">key</span>]
}
</code></pre></div><h2 id="练习web-爬虫">练习：Web 爬虫</h2>
<p>在这个练习中，我们将会使用 Go 的并发特性来并行化一个 Web 爬虫。</p>
<p>修改 <code>Crawl</code> 函数来并行地抓取 URL，并且保证不重复。</p>
<p><em>提示</em>：你可以用一个 map 来缓存已经获取的 URL，但是要注意 map 本身并不是并发安全的！</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;fmt&#34;</span>
)

<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Fetcher</span> <span style="color:#66d9ef">interface</span> {
	<span style="color:#75715e">// Fetch 返回 URL 的 body 内容，并且将在这个页面上找到的 URL 放到一个 slice 中。
</span><span style="color:#75715e"></span>	<span style="color:#a6e22e">Fetch</span>(<span style="color:#a6e22e">url</span> <span style="color:#66d9ef">string</span>) (<span style="color:#a6e22e">body</span> <span style="color:#66d9ef">string</span>, <span style="color:#a6e22e">urls</span> []<span style="color:#66d9ef">string</span>, <span style="color:#a6e22e">err</span> <span style="color:#66d9ef">error</span>)
}

<span style="color:#75715e">// Crawl 使用 fetcher 从某个 URL 开始递归的爬取页面，直到达到最大深度。
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">Crawl</span>(<span style="color:#a6e22e">url</span> <span style="color:#66d9ef">string</span>, <span style="color:#a6e22e">depth</span> <span style="color:#66d9ef">int</span>, <span style="color:#a6e22e">fetcher</span> <span style="color:#a6e22e">Fetcher</span>) {
	<span style="color:#75715e">// TODO: 并行的抓取 URL。
</span><span style="color:#75715e"></span>	<span style="color:#75715e">// TODO: 不重复抓取页面。
</span><span style="color:#75715e"></span>        <span style="color:#75715e">// 下面并没有实现上面两种情况：
</span><span style="color:#75715e"></span>	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">depth</span> <span style="color:#f92672">&lt;=</span> <span style="color:#ae81ff">0</span> {
		<span style="color:#66d9ef">return</span>
	}
	<span style="color:#a6e22e">body</span>, <span style="color:#a6e22e">urls</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">fetcher</span>.<span style="color:#a6e22e">Fetch</span>(<span style="color:#a6e22e">url</span>)
	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">err</span>)
		<span style="color:#66d9ef">return</span>
	}
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;found: %s %q\n&#34;</span>, <span style="color:#a6e22e">url</span>, <span style="color:#a6e22e">body</span>)
	<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">u</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">urls</span> {
		<span style="color:#a6e22e">Crawl</span>(<span style="color:#a6e22e">u</span>, <span style="color:#a6e22e">depth</span><span style="color:#f92672">-</span><span style="color:#ae81ff">1</span>, <span style="color:#a6e22e">fetcher</span>)
	}
	<span style="color:#66d9ef">return</span>
}
</code></pre></div><h2 id="接下来去哪">接下来去哪？</h2>
<p>你可以从<a href="https://go-zh.org/doc/install/">安装 Go</a> 开始。</p>
<p>一旦安装了 Go，Go <a href="https://go-zh.org/doc/">文档</a>是一个极好的 应当继续阅读的内容。 它包含了参考、指南、视频等等更多资料。</p>
<p>了解如何组织 Go 代码并在其上工作，参阅<a href="https://www.youtube.com/watch?v=XCsL89YtqCs">此视频</a>，或者阅读<a href="https://go-zh.org/doc/code.html">如何编写 Go 代码</a>。</p>
<p>如果你需要标准库方面的帮助，请参考<a href="https://go-zh.org/pkg/">包手册</a>。如果是语言本身的帮助，阅读<a href="https://go-zh.org/ref/spec">语言规范</a>是件令人愉快的事情。</p>
<p>进一步探索 Go 的并发模型，参阅 <a href="https://www.youtube.com/watch?v=f6kdp27TYZs">Go 并发模型</a>(<a href="https://talks.go-zh.org/2012/concurrency.slide">幻灯片</a>)以及<a href="https://www.youtube.com/watch?v=QDDwwePbDtw">深入 Go 并发模型</a>(<a href="https://talks.go-zh.org/2013/advconc.slide">幻灯片</a>)并阅读<a href="https://go-zh.org/doc/codewalk/sharemem/">通过通信共享内存</a>的代码之旅。</p>
<p>想要开始编写 Web 应用，请参阅<a href="https://vimeo.com/53221558">一个简单的编程环境</a>(<a href="https://talks.go-zh.org/2012/simple.slide">幻灯片</a>)并阅读<a href="https://go-zh.org/doc/articles/wiki/">编写 Web 应用</a>的指南。</p>
<p><a href="https://go-zh.org/doc/codewalk/functions/">函数：Go 中的一等公民</a>展示了有趣的函数类型。</p>
<p><a href="https://blog.go-zh.org/">Go 博客</a>有着众多关于 Go 的文章和信息。</p>
<p><a href="https://www.mikespook.com/tag/golang/">mikespook 的博客</a>中有大量中文的关于 Go 的文章和翻译。</p>
<p>开源电子书 <a href="https://github.com/astaxie/build-web-application-with-golang">Go Web 编程</a>和 <a href="https://github.com/Unknwon/the-way-to-go_ZH_CN">Go 入门指南</a>能够帮助你更加深入的了解和学习 Go 语言。</p>
<p>访问 <a href="https://go-zh.org/">go-zh.org</a> 了解更多内容。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go">

</code></pre></div>
        </div>

        
<div class="post-archive">
    <ul class="post-copyright">
        <li><strong>原文作者：</strong><a rel="author" href="https://luckly.work/">luckly</a></li>
        <li style="word-break:break-all"><strong>原文链接：</strong><a href="https://luckly.work/post/go_basic/35%E5%88%86%E9%92%9F%E6%95%99%E4%BD%A0%E5%AD%A6%E4%BC%9Ago/">https://luckly.work/post/go_basic/35%E5%88%86%E9%92%9F%E6%95%99%E4%BD%A0%E5%AD%A6%E4%BC%9Ago/</a></li>
        <li><strong>版权声明：</strong>本作品采用<a rel="license" href="https://creativecommons.org/licenses/by-nc-nd/4.0/">知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议</a>进行许可，非商业转载请注明出处（作者，原文链接），商业转载请联系作者获得授权。</li>
    </ul>
</div>
<br/>



        

<div class="post-archive">
    <h2>See Also</h2>
    <ul class="listing">
        
        <li><a href="/post/go_gorm/GORM-CRUD%E6%8C%87%E5%8D%97/">gorm的crud指南</a></li>
        
        <li><a href="/post/go_gorm/gorm%E7%9A%84%E5%AE%9A%E4%B9%89/">gorm的定义</a></li>
        
        <li><a href="/post/go_gorm/CRUD%E7%9A%84%E6%9F%A5%E8%AF%A2%E6%93%8D%E4%BD%9C/">gorm的查询</a></li>
        
        <li><a href="/post/go_gorm/%E8%BF%9E%E6%8E%A5%E6%95%B0%E6%8D%AE%E5%BA%93/">gorm连接数据库</a></li>
        
        <li><a href="/post/go/go%E7%A0%B4%E8%A7%A3/">Go破解</a></li>
        
    </ul>
</div>


        <div class="post-meta meta-tags">
            
            <ul class="clearfix">
                
                <li><a href='/tags/go'>go</a></li>
                
            </ul>
            
        </div>
    </article>
    
    

    
    
    <div class="post bg-white">
      <script src="https://utteranc.es/client.js"
            repo= "https://github.com/ITmxs/repo"
            issue-term="pathname"
            theme="github-light"
            crossorigin="anonymous"
            async>
      </script>
    </div>
    
</div>

                    <footer id="footer">
    <div>
        &copy; 2021 <a href="https://luckly.work/">早起的年轻人 By luckly</a>
        
        | <a rel="nofollow" target="_blank" href="http://beian.miit.gov.cn/">粤ICP备2021号-1</a>
        
    </div>
    <br />
    <div>
        <div class="github-badge">
            <a href="https://juejin.cn/user/3843548384077192" target="_black" rel="nofollow"><span class="badge-subject">Powered by</span><span class="badge-value bg-blue">掘金</span></a>
        </div>
        <div class="github-badge">
            <a href="https://space.bilibili.com/480883651" target="_black"><span class="badge-subject">Design by</span><span class="badge-value bg-brightgreen">早起的年轻人</span></a>
        </div>
        <div class="github-badge">
            <a href="https://cloud.tencent.com/developer/user/6702670" target="_black"><span class="badge-subject">Theme</span><span class="badge-value bg-yellowgreen">云社区</span></a>
        </div>
    </div>
</footer>


    
    <script type="text/javascript">
        window.MathJax = {
            tex2jax: {
                inlineMath: [['$', '$']],
                processEscapes: true
                }
            };
    </script>
    <script src='https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML' async></script><script src="https://cdn.bootcdn.net/ajax/libs/fancybox/3.5.7/jquery.fancybox.min.js"></script>

<a id="rocket" href="#top"></a>
<script type="text/javascript" src='/js/totop.js?v=0.0.0' async=""></script>



    <script type="text/javascript" src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js" async></script>




    <script src='/js/douban.js'></script>
    <script src="/js/copy-to-clipboard.js"></script>

                </div>

                <div id="secondary">
    <section class="widget">
        <form id="search" action='https://luckly.work/search/' method="get" accept-charset="utf-8" target="_blank" _lpchecked="1">
      
      <input type="text" name="q" maxlength="20" placeholder="Search">
      <input type="hidden" name="sitesearch" value="https://luckly.work/">
      <button type="submit" class="submit icon-search"></button>
</form>
    </section>
    
    <section class="widget">
        <h3 class="widget-title">最近文章</h3>
<ul class="widget-list">
    
    <li>
        <a href="https://luckly.work/post/nginx/nginx%E6%96%87%E4%BB%B6%E5%86%85%E5%AE%B9/" title="Nginx文件内容">Nginx文件内容</a>
    </li>
    
    <li>
        <a href="https://luckly.work/post/nginx/nginx%E6%9E%81%E7%AE%80%E6%95%99%E7%A8%8B/" title="Nginx极简教程">Nginx极简教程</a>
    </li>
    
    <li>
        <a href="https://luckly.work/post/nginx/%E5%8D%81%E5%88%86%E9%92%9F%E5%85%A5%E9%97%A8nginx/" title="十分钟入门Nginx">十分钟入门Nginx</a>
    </li>
    
    <li>
        <a href="https://luckly.work/post/go/Goland%E8%BF%9C%E7%A8%8B%E5%BC%80%E5%8F%91%E9%85%8D%E7%BD%AE/" title="Goland远程开发配置">Goland远程开发配置</a>
    </li>
    
    <li>
        <a href="https://luckly.work/post/%E8%AF%BB%E4%B9%A6/%E5%9F%9F%E5%90%8D%E8%A7%A3%E6%9E%90/" title="域名解析">域名解析</a>
    </li>
    
    <li>
        <a href="https://luckly.work/post/git/%E6%8F%90%E4%BA%A4%E8%BF%87%E7%A8%8B%E7%9C%81%E7%95%A5%E6%9F%90%E4%BA%9B%E6%96%87%E4%BB%B6/" title="提交过程省略某些文件">提交过程省略某些文件</a>
    </li>
    
    <li>
        <a href="https://luckly.work/post/flutter_tips/Flutter_DropdownButton%E7%A4%BA%E4%BE%8B/" title="Flutter_DropdownButton示例">Flutter_DropdownButton示例</a>
    </li>
    
    <li>
        <a href="https://luckly.work/post/flutter_tips/Flutter_ExpansionPanelList%E5%92%8CExpansionPanelList.radio%E7%A4%BA%E4%BE%8B/" title="Flutter_ExpansionPanelList和ExpansionPanelList">Flutter_ExpansionPanelList和ExpansionPanelList</a>
    </li>
    
    <li>
        <a href="https://luckly.work/post/flutter_tips/Flutter%E5%BE%AE%E4%BF%A1%E5%88%86%E4%BA%AB%E9%93%BE%E6%8E%A5%E8%B7%B3%E5%9B%9EApp%E6%8C%87%E5%AE%9A%E9%A1%B5%E9%9D%A2/" title="Flutter微信分享链接跳回App指定页面">Flutter微信分享链接跳回App指定页面</a>
    </li>
    
    <li>
        <a href="https://luckly.work/post/%E4%BF%A1%E6%81%AF%E7%B3%BB%E7%BB%9F/%E5%A4%96%E5%8C%85%E5%8F%AF%E8%83%BD%E7%9A%84%E9%97%AE%E9%A2%98/" title="外包可能的问题">外包可能的问题</a>
    </li>
    
</ul>
    </section>

    

    <section class="widget">
        <h3 class="widget-title"><a href='/categories/'>分类</a></h3>
<ul class="widget-list">
    
    <li><a href="https://luckly.work/categories/Flutter/">Flutter (326)</a></li>
    
    <li><a href="https://luckly.work/categories/IT/">IT (2)</a></li>
    
    <li><a href="https://luckly.work/categories/Kotlin/">Kotlin (2)</a></li>
    
    <li><a href="https://luckly.work/categories/Mysql/">Mysql (1)</a></li>
    
    <li><a href="https://luckly.work/categories/nginx/">nginx (1)</a></li>
    
    <li><a href="https://luckly.work/categories/Vue/">Vue (6)</a></li>
    
    <li><a href="https://luckly.work/categories/YouTube%E8%A7%86%E9%A2%91%E4%B8%8B%E8%BD%BD/">YouTube视频下载 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/android/">android (6)</a></li>
    
    <li><a href="https://luckly.work/categories/dart/">dart (96)</a></li>
    
    <li><a href="https://luckly.work/categories/Flutter/">Flutter (28)</a></li>
    
    <li><a href="https://luckly.work/categories/gin/">gin (25)</a></li>
    
    <li><a href="https://luckly.work/categories/git/">git (4)</a></li>
    
    <li><a href="https://luckly.work/categories/Go/">Go (102)</a></li>
    
    <li><a href="https://luckly.work/categories/gorm/">gorm (4)</a></li>
    
    <li><a href="https://luckly.work/categories/grpc/">grpc (1)</a></li>
    
    <li><a href="https://luckly.work/categories/html/">html (3)</a></li>
    
    <li><a href="https://luckly.work/categories/ios/">ios (1)</a></li>
    
    <li><a href="https://luckly.work/categories/linux/">linux (1)</a></li>
    
    <li><a href="https://luckly.work/categories/nginx/">nginx (6)</a></li>
    
    <li><a href="https://luckly.work/categories/python/">python (35)</a></li>
    
    <li><a href="https://luckly.work/categories/read/">读书笔记 (6)</a></li>
    
    <li><a href="https://luckly.work/categories/redis/">redis (2)</a></li>
    
    <li><a href="https://luckly.work/categories/%E4%B8%AA%E4%BA%BA%E8%B5%84%E6%96%99/">个人资料 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E4%B9%A6%E5%8D%95/">书单 (8)</a></li>
    
    <li><a href="https://luckly.work/categories/%E4%B9%A6%E8%AF%84/">书评 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E4%BF%A1%E6%81%AF%E7%B3%BB%E7%BB%9F%E7%AE%A1%E7%90%86%E5%B8%88/">信息系统管理师 (19)</a></li>
    
    <li><a href="https://luckly.work/categories/%E4%BF%A1%E6%81%AF%E7%B3%BB%E7%BB%9F%E9%A1%B9%E7%9B%AE%E7%AE%A1%E7%90%86%E5%B8%88/">信息系统项目管理师 (25)</a></li>
    
    <li><a href="https://luckly.work/categories/%E5%8E%9F%E5%88%99/">原则 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E5%8E%9F%E7%94%9F%E9%80%9A%E8%AE%AF/">原生通讯 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E5%9F%BA%E7%A1%80/">基础 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E5%A4%8D%E5%88%A9%E6%95%88%E5%BA%94/">复利效应 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B/">安装教程 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E5%B0%91%E6%9C%89%E4%BA%BA%E8%B5%B0%E7%9A%84%E8%B7%AF/">少有人走的路 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E5%BF%83%E8%AF%AD/">心语 (3)</a></li>
    
    <li><a href="https://luckly.work/categories/%E6%8F%92%E4%BB%B6/">插件 (2)</a></li>
    
    <li><a href="https://luckly.work/categories/%E6%95%99%E5%AD%A6/">教学 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E7%8E%8B%E9%98%B3%E6%98%8E/">王阳明 (3)</a></li>
    
    <li><a href="https://luckly.work/categories/%E7%94%B5%E5%AD%90%E4%B9%A6/">电子书 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E7%99%BB%E9%99%86%E8%A1%A8%E5%8D%95/">登陆表单 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E7%A8%BB%E7%9B%9B%E5%92%8C%E5%A4%AB/">稻盛和夫 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E7%A9%B7%E7%88%B8%E7%88%B8%E5%AF%8C%E7%88%B8%E7%88%B8/">穷爸爸富爸爸 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E7%B2%BE%E8%BF%9B/">精进 (3)</a></li>
    
    <li><a href="https://luckly.work/categories/%E7%BC%96%E7%A8%8B/">编程 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E8%99%9A%E5%B9%BB/">虚幻 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E8%B4%A2%E5%8A%A1%E8%87%AA%E7%94%B1%E4%B9%8B%E8%B7%AF/">财务自由之路 (2)</a></li>
    
    <li><a href="https://luckly.work/categories/%E8%B7%91%E6%AD%A5/">跑步 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E8%B7%AF%E7%94%B1%E4%BC%A0%E5%8F%82/">路由传参 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E8%B7%AF%E7%BA%BF/">路线 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E8%BD%AF%E4%BB%B6%E5%AE%9E%E6%96%BD/">软件实施 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E9%98%B3%E6%98%8E%E5%BF%83%E5%AD%A6/">阳明心学 (3)</a></li>
    
    <li><a href="https://luckly.work/categories/%E9%A1%B9%E7%9B%AE/">项目 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E9%AD%85%E5%8A%9B/">魅力 (1)</a></li>
    
</ul>
    </section>

    <section class="widget">
        <h3 class="widget-title"><a href='/tags/'>标签</a></h3>
<div class="tagcloud">
    
    <a href="https://luckly.work/tags/flutter/">flutter</a>
    
    <a href="https://luckly.work/tags/IT/">IT</a>
    
    <a href="https://luckly.work/tags/Kotlin/">Kotlin</a>
    
    <a href="https://luckly.work/tags/Mysql/">Mysql</a>
    
    <a href="https://luckly.work/tags/nginx/">nginx</a>
    
    <a href="https://luckly.work/tags/Vue/">Vue</a>
    
    <a href="https://luckly.work/tags/YouTube%E8%A7%86%E9%A2%91%E4%B8%8B%E8%BD%BD/">YouTube视频下载</a>
    
    <a href="https://luckly.work/tags/android/">android</a>
    
    <a href="https://luckly.work/tags/dart/">dart</a>
    
    <a href="https://luckly.work/tags/flutter/">flutter</a>
    
    <a href="https://luckly.work/tags/gin/">gin</a>
    
    <a href="https://luckly.work/tags/git/">git</a>
    
    <a href="https://luckly.work/tags/go/">go</a>
    
    <a href="https://luckly.work/tags/gorm/">gorm</a>
    
    <a href="https://luckly.work/tags/grpc/">grpc</a>
    
    <a href="https://luckly.work/tags/html/">html</a>
    
    <a href="https://luckly.work/tags/ios/">ios</a>
    
    <a href="https://luckly.work/tags/linux/">linux</a>
    
    <a href="https://luckly.work/tags/nginx/">nginx</a>
    
    <a href="https://luckly.work/tags/python/">python</a>
    
    <a href="https://luckly.work/tags/redis/">redis</a>
    
    <a href="https://luckly.work/tags/%E4%B8%AA%E4%BA%BA%E8%B5%84%E6%96%99/">个人资料</a>
    
    <a href="https://luckly.work/tags/%E4%B9%A6%E5%8D%95/">书单</a>
    
    <a href="https://luckly.work/tags/%E4%B9%A6%E8%AF%84/">书评</a>
    
    <a href="https://luckly.work/tags/%E4%BF%A1%E6%81%AF%E7%B3%BB%E7%BB%9F%E7%AE%A1%E7%90%86%E5%B8%88/">信息系统管理师</a>
    
    <a href="https://luckly.work/tags/%E4%BF%A1%E6%81%AF%E7%B3%BB%E7%BB%9F%E9%A1%B9%E7%9B%AE%E7%AE%A1%E7%90%86%E5%B8%88/">信息系统项目管理师</a>
    
    <a href="https://luckly.work/tags/%E5%85%A5%E9%97%A8/">入门</a>
    
    <a href="https://luckly.work/tags/%E5%8E%9F%E5%88%99/">原则</a>
    
    <a href="https://luckly.work/tags/%E5%8E%9F%E7%94%9F%E9%80%9A%E8%AE%AF/">原生通讯</a>
    
    <a href="https://luckly.work/tags/%E5%9F%BA%E7%A1%80/">基础</a>
    
    <a href="https://luckly.work/tags/%E5%A4%8D%E5%88%A9%E6%95%88%E5%BA%94/">复利效应</a>
    
    <a href="https://luckly.work/tags/%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B/">安装教程</a>
    
    <a href="https://luckly.work/tags/%E5%B0%91%E6%9C%89%E4%BA%BA%E8%B5%B0%E7%9A%84%E8%B7%AF/">少有人走的路</a>
    
    <a href="https://luckly.work/tags/%E5%BF%83%E8%AF%AD/">心语</a>
    
    <a href="https://luckly.work/tags/%E6%8F%92%E4%BB%B6/">插件</a>
    
    <a href="https://luckly.work/tags/%E6%95%99%E5%AD%A6/">教学</a>
    
    <a href="https://luckly.work/tags/%E7%8E%8B%E9%98%B3%E6%98%8E/">王阳明</a>
    
    <a href="https://luckly.work/tags/%E7%94%B5%E5%AD%90%E4%B9%A6/">电子书</a>
    
    <a href="https://luckly.work/tags/%E7%99%BB%E9%99%86%E8%A1%A8%E5%8D%95/">登陆表单</a>
    
    <a href="https://luckly.work/tags/%E7%A8%BB%E7%9B%9B%E5%92%8C%E5%A4%AB/">稻盛和夫</a>
    
    <a href="https://luckly.work/tags/%E7%A9%B7%E7%88%B8%E7%88%B8%E5%AF%8C%E7%88%B8%E7%88%B8/">穷爸爸富爸爸</a>
    
    <a href="https://luckly.work/tags/%E7%B2%BE%E8%BF%9B/">精进</a>
    
    <a href="https://luckly.work/tags/%E7%BC%96%E7%A8%8B/">编程</a>
    
    <a href="https://luckly.work/tags/%E8%99%9A%E5%B9%BB/">虚幻</a>
    
    <a href="https://luckly.work/tags/%E8%AF%97/">诗</a>
    
    <a href="https://luckly.work/tags/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/">读书笔记</a>
    
    <a href="https://luckly.work/tags/%E8%B4%A2%E5%8A%A1%E8%87%AA%E7%94%B1%E4%B9%8B%E8%B7%AF/">财务自由之路</a>
    
    <a href="https://luckly.work/tags/%E8%B7%91%E6%AD%A5/">跑步</a>
    
    <a href="https://luckly.work/tags/%E8%B7%AF%E7%94%B1%E4%BC%A0%E5%8F%82/">路由传参</a>
    
    <a href="https://luckly.work/tags/%E8%B7%AF%E7%BA%BF/">路线</a>
    
    <a href="https://luckly.work/tags/%E8%BD%AF%E4%BB%B6%E5%AE%9E%E6%96%BD/">软件实施</a>
    
    <a href="https://luckly.work/tags/%E9%80%9A%E8%AE%AF%E5%BD%95/">通讯录</a>
    
    <a href="https://luckly.work/tags/%E9%98%B3%E6%98%8E%E5%BF%83%E5%AD%A6/">阳明心学</a>
    
    <a href="https://luckly.work/tags/%E9%A1%B9%E7%9B%AE/">项目</a>
    
    <a href="https://luckly.work/tags/%E9%AD%85%E5%8A%9B/">魅力</a>
    
</div>
    </section>

    
<section class="widget">
    <h3 class="widget-title">友情链接</h3>
    <ul class="widget-list">
        
        <li>
            <a target="_blank" href="http://www.topgoer.com/" title="枯藤">枯藤</a>
        </li>
        
        <li>
            <a target="_blank" href="https://gorm.cn/zh_CN/docs/index.html" title="gorm">gorm</a>
        </li>
        
        <li>
            <a target="_blank" href="https://docs.python.org/zh-cn/3/tutorial/index.html" title="python">python</a>
        </li>
        
        <li>
            <a target="_blank" href="https://www.liwenzhou.com/" title="李文周">李文周的博客</a>
        </li>
        
        <li>
            <a target="_blank" href="http://www.xbzweb.com/" title="小包子的博客">小包子的博客</a>
        </li>
        
        <li>
            <a target="_blank" href="https://www.flysnow.org/" title="飞雪无情的博客">飞雪无情的博客</a>
        </li>
        
        <li>
            <a target="_blank" href="https://sliverhorn.com/" title="sliverhorn的博客">sliverhorn的博客</a>
        </li>
        
        <li>
            <a target="_blank" href="http://yuedu.baidu.com/ebook/14a722970740be1e640e9a3e" title="Android Gradle权威指南">Android Gradle权威指南</a>
        </li>
        
        <li>
            <a target="_blank" href="https://gesdh.cn/" title="小格子">格子导航</a>
        </li>
        
        <li>
            <a target="_blank" href="https://itachi.xyz/" title="阿林">itachi&#39;s Blog</a>
        </li>
        
        <li>
            <a target="_blank" href="https://darjun.github.io/" title="大俊">大俊Blog</a>
        </li>
        
        <li>
            <a target="_blank" href="https://geektutu.com/post/quick-golang.html" title="极客兔兔">极客兔兔Blog</a>
        </li>
        
        <li>
            <a target="_blank" href="http://zxfcumtcs.github.io/" title="赵雪峰">雪峰Blog</a>
        </li>
        
    </ul>
</section>


    <section class="widget">
        <h3 class="widget-title">其它</h3>
        <ul class="widget-list">
            <li><a href="https://luckly.work/index.xml">文章 RSS</a></li>
        </ul>
    </section>
</div>
            </div>
        </div>
    </div>
</body>

</html>